Why does the compiler try to instantiate a templat

2019-04-18 17:33发布

问题:

Updated below.
The following is the entire code I have in my main.cpp:

template<class T>
struct other_traits;

template<class T>
struct some_traits{
    typedef decltype(&T::operator()) Fty;
    typedef typename other_traits<Fty>::type type;
};

int main(){
}

But I get the following errors with Visual Studio 2010 while g++ compiles just fine:

src\main.cpp(9): error C2146: syntax error : missing ';' before identifier 'type'
--src\main.cpp(10) : see reference to class template instantiation 'some_traits<T>' being compiled
src\main.cpp(9): error C2868: 'some_traits<T>::type' : illegal syntax for using-declaration; expected qualified-name

(I like that last one, total wtf.)

Can I take that as a bug in VC10 or is there any good reason for the early instantiation? Or is it a bug with decltype that makes the compiler think that Fty is not a dependent name?


Update: I tried to cheat the compiler in thinking that Fty is a dependent name using a base class to inherit from:

template<class T>
struct other_traits;

template<class R, class C>
struct other_traits<R (C::*)()>{
    typedef R type;
};

template<class Fty>
struct base_traits{
    typedef typename other_traits<Fty>::type type;
};

template<class T>
struct some_traits
    : public base_traits<decltype(&T::operator())>
{};

But the compiler still tries to instantiate / compile everything on the spot, spewing these errors:

src\main.cpp(13): error C2039: 'type' : is not a member of 'other_traits<T>'
          with
          [
              T=
          ]
          src\main.cpp(19) : see reference to class template instantiation 'base_traits<Fty>' being compiled
          with
          [
              Fty=
          ]
          src\main.cpp(19) : see reference to class template instantiation 'some_traits<T>' being compiled
src\main.cpp(13): error C2146: syntax error : missing ';' before identifier 'type'
src\main.cpp(13): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
src\main.cpp(13): error C2602: 'base_traits<Fty>::type' is not a member of a base class of 'base_traits<Fty>'
          with
          [
              Fty=
          ]
          src\main.cpp(13) : see declaration of 'base_traits<Fty>::type'
          with
          [
              Fty=
          ]
src\main.cpp(13): error C2868: 'base_traits<Fty>::type' : illegal syntax for using-declaration; expected qualified-name
          with
          [
              Fty=
          ]

Note that the template parameters are empty. Any ideas?

回答1:

It seems to be a Bug (if there is not special flag set as mentioned below). Following is an excerpt from Oracle website for C++ templates:

7.2.2

The ISO C++ Standard permits developers to write template classes for which all members may not be legal with a given template argument. As long as the illegal members are not instantiated, the program is still well formed. The ISO C++ Standard Library uses this technique. However, the -template=wholeclass option instantiates all members, and hence cannot be used with such template classes when instantiated with the problematic template arguments.



回答2:

I think you stumbled upon a bug related to premature instantiation when compiler sees decltype



回答3:

template<class T>
struct other_traits; // <-- I don't see a "type" attribute in this struct

template<class T>
struct some_traits{
    typedef decltype(&T::operator()) Fty;
    typedef typename other_traits<Fty>::type type; // <-- Here you are trying to access other_traits<T>::type which doesn't exist
};

int main(){
}


回答4:

You're making one assumption here, that's technically incorrect. let's tackle that first.

You assume that a syntax error means that a template is instantiated. That's not how templates should be compiled. A template is first compiled before instantiation. This is the phase in which non-dependent names are looked up. Syntax errors can certainly be found in this phase. For instance, anything that's necessarily a declaration regardless of template arguments must end with a ;.

Now the correct question is whether the compiler is correct in considering the specializations of other_traits<T>. There are of course no such specializations by line 9, even though there might be specializations later. But would be the relevant point of instantiation for those? I'd have to look that up (sorry, AFS Away From Standardother_traits<T> would be line 9, then there are no specializations, and other_traits<Fty>::type is invalid. If the point of instantiation for other_traits<Fty>::type would be the same as the point of instantiation for some_traits<T>, i.e. none, then other_traits<Fty>::type should be accepted in phase 1.