1752364 Members
5782 Online
108787 Solutions
New Discussion юеВ

Re: HP C++ bug?

 
SOLVED
Go to solution
River Tarnell
Advisor

HP C++ bug?

Hello,

I believe I've found a bug in the OpenVMS C++ compiler. I couldn't find a way to report it on the website, so I'm posting here in the hope that someone from the C++ team is reading ;-)

I'm using C++ V7.3-009 on OpenVMS Alpha V8.3. When I compile this code:

#include

void f(std::string const &a) {}
void f(std::string &b) {}
std::string g() { return "test"; }

int main() {
f(g());
}

I receive this error:

f(g());
..........^
%CXX-W-REFTEMPORARY, initial value of reference to non-const must be an
lvalue
at line number 8 in file DQA0:[users.river]test2.cxx;6

I believe the compiler is in error here, because passing a temporary T to a function taking a T const& is allowed; the compiler should call the first function. Instead, it seems to be ignoring the first function, and calling the second (which correctly gives an error because a temporary cannot be converted to a T&).

I have tested this example with Comeau C++ and GNU C++, both of which compile it correctly.
4 REPLIES 4
Kris Clippeleyr
Honored Contributor

Re: HP C++ bug?

River,

> I believe the compiler is in error here

I believe there is cause for discussion here.
When interpreting the "f(g());" construct, the compiler has to decide which one of the two variants of the function "f" it should take. Depending on the return type of the function "g" (which is a "std::string"), the argument of the second variant matches more closely than the argument of the 1st variant (which has the "const").
Why not help the compiler a bit by type casting like "f((const std::string &)g());"

Hope this helps.
Kris (aka Qkcl)
I'm gonna hit the highway like a battering ram on a silver-black phantom bike...
River Tarnell
Advisor

Re: HP C++ bug?

I don't agree; I believe the compiler much choose the first function. This is what the C++ standard (1998 edition) has to say about overload resolution of free functions:

Firstly, section 13.3.1.1.1, describing how "candidate functions" for an overloaded call are selected:
[...] If the name resolves to a nonmember function declaration, that function and its overloaded declarations constitute the set of candidate functions

So, we start with both overloads of "f" as candidate functions.

Then, according to 13.3, paragraph 3:

[...] once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases:
├в First, a subset of the candidate functions├в those that have the proper number of arguments and meet certain other conditions├в is selected to form a set of viable functions (13.3.2).
├в Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.

13.3.2 defines a "viable function":

2 First, to be a viable function, a candidate function shall have enough parameters to agree in number with the
arguments in the list.
3 Second, for F to be a viable function, there shall exist for each argument an implicit conversion sequence
(13.3.3.1) that converts that argument to the corresponding parameter of F. If the parameter has reference
type, the implicit conversion sequence includes the operation of binding the reference, and the fact that a
reference to nonconst cannot be bound to an rvalue can affect the viability of the function (see 13.3.3.1.4).

2. is true for both overloads of f; they both have a single argument. However, 13.3.3.1 makes it clear that 3. is not true for the second f:

13.3.3.1:
5 For the case where the parameter type is a reference, see 13.3.3.1.4.
13.3.3.1.4:
3 A standard conversion sequence cannot be formed if it requires binding a reference to nonconst to an rvalue (except when binding an implicit object parameter; see the special rules for that case in 13.3.1).
[Note: this means, for example, that a candidate function cannot be a viable function if it has a nonconst reference parameter (other than the implicit object parameter) and the corresponding argument is a temporary or would require one to be created to initialize the reference (see 8.5.3). ]

The argument - g() - is a temporary of type std::string; therefore, it cannot be bound to the "std::string &" argument of the second f(). Therefore, the second f() is not a viable function, and the compiler must discard it. The only remaining viable function -- and therefore the best -- is the first f().
Robert Brooks_1
Honored Contributor

Re: HP C++ bug?

I couldn't find a way to report it on the website, so I'm posting here in the hope that someone from the C++ team is reading ;-)

--

I'm not with the C++ compiler team, but I've asked someone in VMS Engineering who does work with various compilers to take a look at this thread.


-- Rob
Robert Brooks_1
Honored Contributor
Solution

Re: HP C++ bug?

A reply . . .

The default is /standard=relaxed, which enables an
anachronism that our previous versions of the compiler
supported, and we chose not to break existing customer
code compiled with default options when newer versions
implemented the standard behavior.

The choices are to compile with /standard=strict, or
add the undocumented option /switch=no_nonconst_ref_anachronism