对不起有趣的标题。
在C ++ 0x之前,使用函数本地结构(“本地类型”)作为模板参数有restrictions。我的问题基本上是否类似的限制适用于匿名结构。具体而言,在特质类的上下文中:
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?
这是否有效且可靠?它汇编了最新版本的GCC和LLVM,但我仍然不安全,这是否严格有效,以及VC ++和ICC是否理解。
答案 0 :(得分:6)
供参考,14.3.1 / 2中链接问题的引用:
本地类型,没有链接的类型, 未命名的类型或复合类型 任何这些类型都不得 用作a的模板参数 模板类型参数。
我的解释是typedef struct
正在为未命名的类型创建别名,因此它不能用作模板类型参数。进一步注意,另外在C typedef struct {} Foo;
中的处理方式与struct Foo {};
的处理方式截然不同,前两种形式不等同(尽管可以肯定这种差异不会出现在C ++中)。
因此看起来你的第一个例子是有效的(因为它没有使用未命名的类型作为模板类型参数),而第二个和第三个例子在技术上是无效的(因为它们确实将它用作模板类型参数)。 / p>
最后在结束时我不得不问,是否有理由不能命名结构而不是typedef
?
编辑:从7.1.3 / 1开始:
...因此,typedef-name是其同义词 另一种类型。 typedef-name没有 介绍一种新类型的方式 声明(9.1)或枚举声明 确实...
这强烈暗示以这种方式使用typedef
不会引入适合用作模板类型参数的类型。
答案 1 :(得分:4)
在即将推出的标准中,限制已从语言中删除。
中的标准说明了14.3.1 [temp.arg.type] / 1
作为类型的template-parameter的template-argument应为type-id。
typedef是有效的 type-id 。事实上,下一段包含了这样一个例子:
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);
}
(我已经修剪了大多数其他示例)示例显示,未命名的类型可以在类模板和函数模板中用作类模板参数。
答案 2 :(得分:3)
一个typedef
声明,它定义了该类的匿名类和typedef-name,typedef-name是用于链接目的的类的名称。因此,如果该类符合其他标准,则将该类用作模板参数是合法的。
参见C ++ 03标准的7.1.3p5
如果typedef声明定义了 未命名的类(或枚举),第一个 声明定义的typedef-name是该类类型(或枚举 type)用于表示类类型 (或枚举类型)用于链接目的 只(3.5)。 [实施例:
typedef struct { } *ps, S; // S is the class name for linkage purposes
这是C ++ 0x FDIS中的7.1.3p9。
FWIW,此代码与MSVC2010(模数拼写错误)编译正常。
答案 3 :(得分:0)
嗯,这相当于
template <typename T>
struct trait<std::basic_string<T> > {
struct type {
T value;
};
};
这是完全合法的。