4

Suppose the code:

template <class T>
class X {  };

int main(void) {
    X<class {
        int a;
    }> x;
    return 0;
}

g++ 5.1 gives the following error message:

prog.cpp: In function 'int main()':
prog.cpp:5:10: error: types may not be defined in template arguments
  X<class {
          ^
prog.cpp:7:2: error: expected ';' after class definition
  }> x;
  ^
prog.cpp:7:2: error: expected template-argument before ';' token
prog.cpp:7:2: error: expected '>' before ';' token
prog.cpp:7:2: error: 'main()::<anonymous class>' is/uses anonymous type
prog.cpp:7:2: error:   trying to instantiate 'template<class T> class X'
prog.cpp:7:2: error: expected '::' before ';' token
prog.cpp:7:2: error: expected identifier before ';' token
prog.cpp:7:3: error: expected primary-expression before '>' token
  }> x;
   ^
prog.cpp:7:5: error: 'x' was not declared in this scope
  }> x;
     ^

The second line of the error output says that we can't define types in template arguments. Why is it invalid? (I mean, I know it's invalid in the standard, but what's the reason for that?)

jnbrq -Canberk Sönmez
  • 1,790
  • 1
  • 17
  • 29
  • 1
    I don't think the C++ standard allows that, plain and simple. – Violet Giraffe Jan 09 '16 at 22:17
  • 1
    how would that be useful? When deciding if the language supports a feature, there is a balance between the known benefits, possible future usages, level of complexity added to the language and difficulty of implementation. If there is nothing on the left side... you don't just add features for the sake of adding features. – bolov Jan 09 '16 at 22:22
  • 1
    Rather than asking why this is disallowed, try articulating what benefit there would be in allowing your example, that justifies accepting the additional complexity of the language (parsing such constructs) and implementing them in a compiler. Such a feature might be exploitable in code obfuscation contests, but that is more of an argument against rather than for it. – Peter Jan 09 '16 at 22:48

3 Answers3

6

§14.3.1/2 from the C++ 03 standard says:

A local type, a type with no linkage, an unnamed type or a type compounded from any of these types shall not be used as a template-argument for a template type-parameter.

Which basically means you can't do what you tried to do - using an unnamed type as a template argument.

I'm pretty sure the C++ 11 and C++ 14 standards did not revise that paragraph, but feel free to verify that.

Update: C++ 11 did lift the local type restriction - that's allowed for template parameters now, but not the anonymous type: https://stackoverflow.com/a/4573104/634821

Community
  • 1
  • 1
Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
3

There is no good reason to allow it, although I am not sure whether there is or not a strong technical reason for the limitation. In C++98 restrictions were added on types that can be used as template arguments that might have been stronger than needed, partly due to fear of unknown (how can we handle mangling of types that have no name?).

C++11 added lambdas to the language, which can be used in templates. Lambdas are local types, and thus the limitation on local types has been lifted. But they are not unnamed, their names are just unutterable and generated by the compiler.

The same techniques to generate those names and use them for mangling may be usable in your particular case, although they may not be generalizable for all unnamed types --compilers generate lambda names using among other information the function name, which due to ODR is guaranteed to allow for unique names. In the general case an unnamed type could be created at namespace level, where it would be harder to determine the right way of mangling the type.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
0

There are several errors in the lines:

X<class {
    int a;
}> x;
  1. You are trying to define a class in a place where it is not legal.
  2. You are not giving a typename to instantiate X.
  3. You are trying to use an unnamed class to instantiate X.

The simplest fix is to use:

struct A { int a; };
X<A> x;

if you are able to use a C++11 compiler. If you don't have access to a C++11 compiler, you need to move the definition of struct A outside main.

Update, in response to OP's comment

Allowing the syntax you are suggesting involves a significant change to the syntax for defining a class. Currently, you need a statement to define a class, even an unnamed class.

struct A { ... } ;
            //   ^^ Need this to define a class/struct

struct { ... } obj ;
               //  ^^ Need this to define an unnamed class/struct too.

With your code

X<class {int a} > x;
          //  ^^ There is no scope for a statement.         
R Sahu
  • 204,454
  • 14
  • 159
  • 270