首先是一些代码,然后是一些上下文,然后是问题:
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
expect是template <typename...>
,这一事实从一开始就让我担心。然而,这个例子运行起来非常方便,因为否则像apply1
,apply2
这样的元函数就会涉及到更多的东西。
另一方面,这样的模板别名在现实世界的代码中会导致严重的问题,我不能在这里重现这些问题:频繁的内部编译器错误,以及不太频繁的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;
这两种情况下都能很好地编译并打印0
,在clang 3.3、gcc 4.8.1、gcc 4.9.0上。
在大多数情况下,我的变通方法是在别名之前引入一个中间模板结构。然而,我现在正在尝试使用元函数来参数化通用SFINAE测试,在这种情况下,我必须直接使用别名,因为结构不应该被实例化。为了获得一个概念,实际代码的一部分是here。
发布于 2013-11-29 08:24:19
ISO C++11 14.3.3/1:
模板模板参数的模板参数应该是类模板或别名模板表达式的名称,表示为id-。
另外,对于可变模板模板参数,我没有看到任何特殊的异常。
另一方面,这样的模板别名在现实世界的代码中会导致严重的问题,我不能在这里重现:频繁的内部编译器错误,
的意外行为较少(仅在更高级的SFINAE测试中)。
问题的根源可能在其他地方。你应该尝试本地化导致内部编译器错误的代码--只需一个接一个地删除不相关的部分(或者使用某种二进制搜索,即分而治之)-并检查错误是否仍然存在于每个阶段。
至于GCC 4.9.0错误,请尝试更改
template <typename... T>
using map = F <T...>;
至
template <typename... U>
using map = F <U...>;
也许这将有助于理解GCC所看到的。
https://stackoverflow.com/questions/20253473
复制相似问题