tags:

views:

278

answers:

3

I tried this example from "C++ Template - The Complete Guide" by Nicolai M. Josuttis

#include <iostream>

using namespace std;

template< typename T >
class List {
};

typedef enum { RED, GREEN, BLUE } *color_ptr;

int main() {
    struct Local {
        int x;
    };

    List< Local > l; // error : local type in template argument
    List< color_ptr > l1; // error : unamed type in template argument.

    return 0;
}

With g++ under Ubuntu 9.04, I got compiler errors. However, this piece of code was compiled successfully in Visual C++ 2008. And as I read from the book : "Template type arguments are the "values" specified for template type parameters. Most commonly used types can be used as template arguments, but there are two exceptions: 1. Local classes and enumerations( in other words, types declared in a function definition ) cannot be involved in template type arguments. 2. Types that involve unnamed class types or unnamed enumeration types cannot be template type arguments ( unnamed classes or enumerations that are given a name through a typedef declaration are OK. ) So is there a mistake in Visual C++ ?

A: 

Check to see if you are compiling with Microsoft extensions (/Ze).

Drew Hoskins
+1  A: 
Alex Martelli
Clearly MS are patriots. Perhaps I should call it BSI C++, especially when I'm referring to my bound copy :-)
Steve Jessop
+3  A: 

There are many other cases where you find that book diverge from the behavior of VC++. Examples are the typename and template ambiguity tools and the binding of non-const references to rvalues.

In this case, of course the behavior of G++ is correct, as the book says. Try the following changes

typedef enum color_type { RED, GREEN, BLUE } *color_ptr;

template< typename T >
class List {
};

// not really local anymore :)
struct Local { int x; };
int main() {
  List< Local > l;
  List< color_type > l1;
}

The next C++ Standard (C++0x) allows local types as template arguments.


Please note what the book means with giving a name to a type with typedef. This does not apply to the following, because the name A does not name the enumeration type, but a pointer type to it.

typedef enum { X } *A;

So, when you use A or in your example color_ptr, then you are not going safe. Technically, that name is a pointer type to a type without linkage, which is not allowed as a template argument.


Note that you may put Local into an unnamed namespace to make the type local to the current translation unit, but still have the type acceptable as a type template argument. That way, if you just want to have a "scratch" type for something like a function object, the struct won't clash with a struct defined in a different file.

namespace {
  // not really local anymore, but "translation unit local" :)
  struct Local { int x; };
}
Johannes Schaub - litb