Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cast operator function compiles fine in g++ but not in other compilers. Why? [duplicate]

Consider following program:

struct S {
    using T = float;
    operator T() { return 9.9f; }
};
int main() {
    S m;
    S::T t = m;
    t = m.operator T(); // Is this correct ?
}

The program compiles fine in g++ ( See live demo here )

But it fails in compilation in clang++, MSVC++ & Intel C++ compiler

clang++ gives following errors ( See live demo here )

main.cpp:8:20: error: unknown type name 'T'; did you mean 'S::T'?
    t = m.operator T(); // Is this correct ?
                   ^
                   S::T
main.cpp:2:11: note: 'S::T' declared here
    using T = float;

MSVC++ gives following errors ( See live demo here )

source_file.cpp(8): error C2833: 'operator T' is not a recognized operator or type
source_file.cpp(8): error C2059: syntax error: 'newline'

Intel C++ Compiler also rejects this code ( See live demo here )

So, the question is which compiler is right here ? Is g++ incorrect here or other 3 compilers are incorrect here ? What C++ standard says about this ?

like image 736
Destructor Avatar asked Nov 17 '16 15:11

Destructor


1 Answers

[basic.lookup.classref]/7:

If the id-expression is a conversion-function-id, its conversion-type-id is first looked up in the class of the object expression and the name, if found, is used. Otherwise it is looked up in the context of the entire postfix-expression. In each of these lookups, only names that denote types or templates whose specializations are types are considered. [ Example:

struct A { };
namespace N {
  struct A {
    void g() { }
    template <class T> operator T();
  };
}

int main() {
  N::A a;
  a.operator A();  // calls N::A::operator N::A
}

end example]

This indicates that the example could be fine, although in the above example, A has previously been declared as a type name, visible to main.

This was discussed in core issue 156, filed all the way back in 1999:

How about:

struct A { typedef int T; operator T(); };
struct B : A { operator T(); } b;
void foo() {
  b.A::operator T(); // 2) error T is not found in the context
                     // of the postfix-expression?
}

Is this interpretation correct? Or was the intent for this to be an error only if T was found in both scopes and referred to different entities?

Erwin Unruh: The intent was that you look in both contexts. If you find it only once, that's the symbol. If you find it in both, both symbols must be "the same" in some respect. (If you don't find it, its an error).

So I'd say that Clang is wrong: the intent, as expressed in the wording to some extent, is that we find T, even if only in the class.

like image 158
Columbo Avatar answered Nov 19 '22 16:11

Columbo