Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forward declaration of class used in template function is not compiled by clang++

There is this code:

class A;

template <class T>
void fun() {
   A a;
}

class A { 
public: 
   A() {  } 
};

int main() { 
   fun<int>(); 
   return 0;
}

g++ 4.5 and g++ 4.7 compiles this without error. But clang++ 3.2 (trunk) gives this error:

main.cpp:5:6: error: variable has incomplete type 'A'
   A a;
     ^
main.cpp:1:7: note: forward declaration of 'A'
class A;
      ^

Which compiler is right then according to C++ standard?

like image 398
scdmb Avatar asked Jun 12 '12 09:06

scdmb


3 Answers

Which compiler is right then according to C++ standard?

Both are correct. This is an ill-formed program. Emphasis mine:

N3290 14.6¶9
If a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is done, and if the completeness of that type affects whether or not the program is well-formed or affects the semantics of the program, the program is ill-formed; no diagnostic is required.

That clang++ and other compilers do issue a diagnostic here is a nice-to-have added feature, but a diagnosis is not mandatory. That clause "the program is ill-formed; no diagnostic is required" gives a compiler developer free reign to do just about anything in such circumstances and still be compliant.

like image 60
David Hammen Avatar answered Nov 11 '22 11:11

David Hammen


Clang is correct, as far as I know. At your function fun, you do not know the size of A, and since your allocating an A, you need to know it's size. In my opinion, gcc is way to forgiving here.

like image 35
martiert Avatar answered Nov 11 '22 09:11

martiert


clang++ is using the correct behavior, this is described in section 4.6/9 of the standard (n1905).


Templates 14.6/9 Name resolution

If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation.


To put things in simpler terms; if the name is not dependent on a template-parameter it should be in scope where the definition is found; therefore you'll need to define A before your definition of template<typename T> void fun ().

like image 1
Filip Roséen - refp Avatar answered Nov 11 '22 10:11

Filip Roséen - refp