【发布时间】:2013-11-27 21:32:02
【问题描述】:
首先是一些代码,然后是一些上下文,然后是问题:
template <typename T> using id = T;
template <template <typename...> class F, typename... T>
using apply1 = F <T...>;
template <template <typename...> class F>
struct apply2
{
template <typename... T>
using map = F <T...>;
};
// ...
cout << apply1 <id, int>() << endl;
cout << apply2 <id>::map <int>() << endl;
clang 3.3 和 gcc 4.8.1 均无错误地编译它,将标识元函数应用于 int,因此两个表达式的计算结果均为默认 int(零)。
id 是 template <typename> 而 apply1、apply2 期望 template <typename...> 的事实首先让我担心。然而,这个例子很方便,因为否则像apply1、apply2 这样的元函数将不得不更多地参与。
另一方面,此类模板别名会导致我无法在此处重现的实际代码中的严重问题:gcc 的内部编译器错误频繁,clang 的意外行为较少(仅在更高级的 SFINAE 测试中)。
经过几个月的反复试验,我现在在(实验性)gcc 4.9.0 上安装并尝试了代码,但出现了错误:
test.cpp: In instantiation of ‘struct apply2<id>’:
test.cpp:17:22: error: pack expansion argument for non-pack parameter ‘T’ of alias template ‘template<class T> using id = T’
using map = F <T...>;
^
好的,所以这段代码似乎一直无效,但是 gcc 以各种方式崩溃而不是报告错误。有趣的是,虽然apply1、apply2 看起来是等价的,但错误只报告给apply2(这在实践中更有用)。至于clang,我真的不能说。
实际上,我似乎别无他法,只能使用 gcc 4.9.0 并更正代码,尽管它会变得更加复杂。
理论上,我想知道标准是怎么说的:这段代码有效吗?如果不是,apply1 的使用是否也无效?还是只有apply2?
编辑
只是为了澄清到目前为止我遇到的所有问题都是指模板别名,而不是模板结构。例如,考虑以下修改:
template <typename T> struct id1 { using type = T; };
// ...
cout << typename apply1 <id1, int>::type() << endl;
cout << typename apply2 <id1>::map <int>::type() << endl;
在clang 3.3、gcc 4.8.1、gcc 4.9.0上,这两种情况下都可以正常编译并打印0。
在大多数情况下,我的解决方法是在别名之前引入一个中间模板结构。但是,我现在尝试使用元函数来参数化通用 SFINAE 测试,在这种情况下,我必须直接使用别名,因为不应该实例化结构。只是想知道,一段实际代码是here。
【问题讨论】:
-
实验性GCC 4.9的错误信息对我来说没有意义,FWIW我认为代码是有效的。
-
谢谢,这个问题与处理
foo、foo2、foo_variadic等特殊情况的模板有关.但是,正如我在上面编辑的那样,我的问题只出现在模板别名中。 -
FWIW,clang++ 3.6.0和g++ 5.1.0都报错。
标签: c++ c++11 variadic-templates template-meta-programming template-aliases