Why does the compiler try to instantiate a template that I don't actually instantiate anywhere?
Asked Answered
R

4

15

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?

Reiche answered 7/6, 2011 at 10:40 Comment(10)
Try rewriting it into typedef typename other_traits<typename Fty>::type type; (just a blind shot).Gasometry
Random guess - try adding more "typename" keywords (and parens) on that line, to indicate that Fty, other_traits<Fty> and other_traits<Fty>::type are all types. It looks a bit like VC++ is doing some error checking before instantiation (which it's allowed to do, to a point), but getting confused - possibly because of the use of "decltype".Relique
it's not because of decltype, it behaves the same without itMethenamine
it gives the exact same error with just this code: struct other_traits; template<class T> struct some_traits { typedef other_traits::type hype; }; (the hype is not a typo, I wanted to check if it got confused with both having the same name)Methenamine
@stjin: Well, obviously that is wrong... it's note a dependent name. Try replacing the decltype(...) simply with T.Reiche
@Xeo: now that is a surprising issue, I would have thought that given that VC++ does not perform the first pass of the two-phases look-up, this should definitely not hamper it.Tenia
If it's any help, codepad (gcc 4.1.2) gives: "Line 6: error: expected identifier before '&' token\n compilation terminated due to -Wfatal-errors."Phalarope
It interprets said line as an access-declaration. I suspect that it thinks that decltype(&T::operator()) is a non-dependent type. All that surprises me though, because I was told that MSVC doesn't really parse templates. So I'm not sure why it rejects that template.Biles
@Johannes: Interesting, huh? Well, the problem can be solved if I pass the decltype(...) as a template parameter to a base class I think. I'll try that asap.Reiche
FWIW, I finally came around to submitting a bug report to Microsoft. Vote up if you can.Reiche
R
2

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.

Robbirobbia answered 7/6, 2011 at 11:28 Comment(1)
This is comforted by the fact that Comeau online compiler finds the original code perfectly legal.Mikes
K
1

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

Kerrikerrie answered 8/6, 2011 at 2:10 Comment(0)
K
0
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(){
}
Kandicekandinsky answered 7/6, 2011 at 13:19 Comment(3)
You don't see it because the struct is opaqueSociolinguistics
I'm not sure I understand you here, opaque would mean that the internal details are in another translation unit/header file. Originator says that all the code in his single file main.cpp so there are no other definitions of the struct elsewhere.Kandicekandinsky
It shouldn't even try to access the other_traits, because Fty is a dependent name on T.Reiche
F
0

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.

Frow answered 7/6, 2011 at 20:27 Comment(2)
Okay, then why is the compiler telling me that it instantiates the template? :| And why is the compilation even relevant when I'm using a dependent name? It should delay the lookup. And, even with partial specializations, how should the compiler know which one to choose? Fty depends on the template parameter, as such it's a dependent name, at least for how I understand it.Reiche
Well, it is MSVC, a compiler famous for not doing two-phase instantiation correctly. Back to the theory, a compiler needs to at least parse your code to determine whether something is in fact a dependent name; you'd be able to have syntax errors before that. E.g. typedef : x - you can't figure out whether x is dependent; the : is already wrong (::x would not be dependent).Frow

© 2022 - 2024 — McMap. All rights reserved.