Anonymous struct in typedef of trait class
Sorry for the funny title.
Prior to C++0x, there are restrictions in the use of function-local structs (“local types”) as template arguments. My question is essentially if similar restrictions apply to anonymous structs. Specifically, in the context开发者_开发百科 of a trait class:
template <typename T>
struct trait;
template <>
struct trait<int> {
typedef int type;
};
template <typename T>
struct trait<std::basic_string<T> > {
typedef struct {
T value;
} type;
};
trait<std::string>::type foo; // Is this valid?
template <typename T>
void f() { }
f<trait<std::string>::type> >(); // Is this?
template <typename T>
void g() { f<typename trait<T>::type>(); }
g<std::string>(); // And this?
Is this valid and reliable? It compiles in recent versions of GCC and LLVM but I’m still insecure whether this is strictly valid, and whether it’s understood by VC++ and ICC.
For reference, the quote from the linked question in 14.3.1/2:
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.
My interpretation is that the typedef struct
is creating an alias to an unnamed type and that it thus can't be used as a template type parameter. Further note that additionally in C typedef struct {} Foo;
is treated rather differently from struct Foo {};
giving precedent that the two forms are not equivalent (although admittedly that difference doesn't appear in C++).
Thus it would appear your first example works (since it's not using the unnamed type as a template type parameter), while the second and third examples would be technically invalid (since they do use it as a template type parameter).
Finally in closing I have to ask, is there a reason you can't name the struct instead of typedef
ing it?
EDIT: From 7.1.3/1:
...A typedef-name is thus a synonym for another type. A typedef-name does not introduce a new type the way a class declaration (9.1) or enum declaration does...
This strongly implies that using typedef
in such a way does not introduce a type suitable for use as a template type-parameter.
In the upcoming standard that restriction is removed from the language. The standard says in
14.3.1 [temp.arg.type] /1
A template-argument for a template-parameter which is a type shall be a type-id.
And a typedef is a valid type-id. As a matter of fact the next paragraph contains such an example:
14.3.1 [temp.arg.type] /2
template <class T> class X { };
template <class T> void f(T t) { }
void f() {
typedef struct { } B;
B b;
X<B> x3;
f(b);
}
(Where I have trimmed most of the other examples) The example shows that an unnamed type can be used as a class template argument both in class templates and function templates.
A typedef
declaration that defines an anonymous class and a typedef-name for that class, the typedef-name is the name of the class for linkage purposes. It is therefore legal to use that class as a template parameter if it meets the other criteria.
See 7.1.3p5 of the C++03 standard
If the typedef declaration defines an unnamed class (or enum), the first typedef-name declared by the decla-ration to be that class type (or enum type) is used to denote the class type (or enum type) for linkage purposes only (3.5). [Example:
typedef struct { } *ps, S; // S is the class name for linkage purposes
This is 7.1.3p9 in the C++0x FDIS.
FWIW, this code compiles OK with MSVC2010 (modulo typos).
Well, that is equivalent to
template <typename T>
struct trait<std::basic_string<T> > {
struct type {
T value;
};
};
which is completely legitimate.
精彩评论