14

The title is pretty self-explanatory, but here's a simplified example:

#include <cstdio>

template <typename T>
struct MyTemplate {

    T member;

    void printMemberSize() {
        printf("%i\n", sizeof(T));
    }

};

int main() {

    MyTemplate<struct { int a; int b; }> t; // <-- compiler doesn't like this

    t.printMemberSize();

    return 0;

}

The compiler complains when I try to use an anonymous struct as a template argument. What's the best way to achieve something like this without having to have a separate, named struct definition?

nonoitall
  • 1,232
  • 1
  • 15
  • 25

2 Answers2

8

You are not allowed to define an unnamed type as a template argument in C++03 or even in C++0x.

The best you can do it to create a named struct local to main (in C++0x1)

1 : You are not allowed to use a local type as template argument in C++03, however C++0x allows it.

Also check out the Defect Report here. The proposed solution mentions

The following types shall not be used as a template-argument for a template type-parameter:

  • a type whose name has no linkage
  • an unnamed class or enumeration type that has no name for linkage purposes (7.1.3 [dcl.typedef])
  • a cv-qualified version of one of the types in this list
  • a type created by application of declarator operators to one of the types in this list
  • a function type that uses one of the types in this list

The compiler complains when I try to use an anonymous struct as a template parameter.

Did you mean template argument? Template parameter is different from template argument.

For example

template < typename T > // T is template parameter
class demo {};

int main()
{
   demo <int> x; // int is template argument
}
Community
  • 1
  • 1
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
  • In C++0x, an object of an unnamed type can be deduced as a template argument, but I don't think an unnamed type can be specified explicitly in the template argument list. – James McNellis Jan 01 '11 at 03:40
  • Prasoon, can you refer me to the right section of the standard please? My test case with an unnamed struct (passed to a typedef, but we all know that a typedef name is not a struct name) compiles just fine. – Ben Voigt Jan 01 '11 at 03:41
  • 2
    @Prasoon: Thanks. Looks like that restriction definitely is removed in C++0x. Still can't define a type inside the template argument list though, which is the question actually posed by the code (as opposed to the title). – Ben Voigt Jan 01 '11 at 04:01
  • Thanks for clarifying argument vs. parameter - I guess I had always just used the terms interchangeably, but yes, I meant argument. I tried using a locally defined, named struct for the template *argument* but the results were the same. (I am using GCC 4.5's C++0x support.) – nonoitall Jan 01 '11 at 04:19
  • Nevermind - evidently this won't work on MinGW 4.5, but it does work on GCC 4.5. – nonoitall Jan 01 '11 at 04:42
6

Your problem isn't that the struct is unnamed, it's that the struct is declared locally. Using local types as template arguments is not permitted in C++03. It will be in C++0x though, so you might try upgrading your compiler.

EDIT: Actually, your problem is that inside a template argument list isn't a legal place to put a class definition, with or without a name, according to the C++ standard.

litb points out that although it fits into the C++0x grammar, defining a type here is forbidden by [dcl.type]:

A type-specifier-seq shall not define a class or enumeration unless it appears in the type-id of an alias-declaration (7.1.3) that is not the declaration of a template-declaration.

simple-template-id:
    template-name < template-argument-list_opt >

template-argument-list:
    template-argument ..._opt
    template-argument-list , template-argument ..._opt

template-argument:
    constant-expression
    type-id
    id-expression

type-id:
    type-specifier-seq abstract-declarator_opt

type-specifier-seq:
    type-specifier attribute-specifier-seq_opt
    type-specifier type-specifier-seq

type-specifier:
    trailing-type-specifier
    class-specifier
    enum-specifier

class-specifier:
    class-head { member-specification_opt }

For a while I had a question about typedef names, but litb cleared that up. They are allowed as template arguments via:

trailing-type-specifier:
    simple-type-specifier
    elaborated-type-specifier
    typename-specifier
    cv-qualifier

simple-type-specifier:
    :: opt nested-name-specifier_opt type-name
    :: opt nested-name-specifier template simple-template-id
    char
    char16_t
    char32_t
    wchar_t
    bool
    short
    int
    long
    signed
    unsigned
    float
    double
    void
    auto
    decltype-specifier

type-name:
    class-name
    enum-name
    typedef-name
    simple-template-id
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Actually I'm using GCC 4.5's C++0x capabilities. Is this feature not be implemented there yet? – nonoitall Jan 01 '11 at 04:14
  • @nonoitall: The [C++0x tag wiki](http://stackoverflow.com/tags/c%2b%2b0x/info) has links to lots of information on the status of C++0x support in several compilers. It says it's supposed to be added in gcc 4.5. The [official gcc release notes](http://gcc.gnu.org/gcc-4.5/changes.html) say "In C++0x mode local and anonymous classes are now allowed as template arguments". You are compiling with the `-std=gnu++0x` option, right? – Ben Voigt Jan 01 '11 at 04:25
  • My bad. Evidently this is something that got left behind on the MinGW port of GCC 4.5. Tried compiling it on a Linux box and it will compile when using a locally defined struct (though using an anonymous struct as an argument still won't fly). /me goes to install Cygwin. – nonoitall Jan 01 '11 at 04:40
  • The "... it shall not appear in the type-id." is just meant to say that "using foo = foo;" is forbidden. It talks about such alias declarations. When resolution for http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1044 is applied, then that text can be removed. – Johannes Schaub - litb Jan 01 '11 at 05:03
  • @Johannes: Thanks! and also "Hey the bat signal worked!" What's your assessment of actually defining a type inside a template argument list? – Ben Voigt Jan 01 '11 at 05:28
  • @Ben 7.1.6/3 last sentence of n3225. – Johannes Schaub - litb Jan 01 '11 at 05:32
  • @Ben I can't actually find where C++03 forbids it. In fact, it seems that GCC doesn't know either, since it actually compiles the following code: `template struct A { }; A< struct B { } >::SomeNonSense int y;`. – Johannes Schaub - litb Jan 01 '11 at 05:59
  • @Johannes: I guess I made the mistake of never trying that at namespace scope... so C++03 compilers correctly rejected a reference to a local class, and C++0x correctly rejected a definition placed there. – Ben Voigt Jan 01 '11 at 06:09
  • @Johannes: I can't parse that line of code either... is there supposed to be a semicolon before `int y;`? – Ben Voigt Jan 01 '11 at 06:13
  • @Ben it's just complete nonsense. GCC should have rejected already when we tried to define the type. It makes no sense at all, that's why GCC internally goes all mad. – Johannes Schaub - litb Jan 01 '11 at 06:18
  • @Johannes: Oh good... I would hate to start the new year having lost my mind ;) – Ben Voigt Jan 01 '11 at 06:25