我一直在使用可变参数模板并注意到以下内容 .
这很好用:
auto t = std::make_tuple(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
这将给出错误(gcc 4.8.2(编辑:Clang 3.4)默认最大深度为256):
auto t2 = std::make_tuple(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17);
但是,直接创建元组将起作用:
std::tuple<int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int,int> t3(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17);
我在尝试创建一个返回模板化类的模板化函数时注意到了这一点 .
template <typename...Arguments>
struct Testing {
std::tuple<Arguments...> t;
Testing(Arguments...args) : t(args...) {}
};
template <typename... Arguments>
Testing<Arguments...> create(Arguments... args) {
return Testing<Arguments...>(args...);
}
在这种情况下,这将工作:
auto t4 = create(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16);
这不会:
auto t5 = create(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17);
1 回答
问题不是
make_tuple
,而是libstdc(gcc4.8.2)中tuple
的移动构造函数 .对于类模板,成员函数仅在使用时实例化 . noexcept规范延迟类似,参见例如CWG issue 1330 .
当从
make_tuple
初始化变量时,移动构造函数被实例化,即使它被省略(例如,检查它是否是不正确的) . 这就是为什么你看到只定义tuple
变量和使用make_tuple
之间的区别 .移动构造函数具有递归实现的条件
noexcept
. 因此,对于每个模板参数,需要恒定数量的附加实例化 . 当超过最大实例化深度时,clang的错误输出的摘录:(支撑自己,文本墙进入)我们在这里可以看到实施例如
is_nothrow_move_constructible
的is_nothrow_move_constructible
,以__is_nt_constructible
实现,依此类推15个实例化级别 . 它打印得像一个调用堆栈,因此您可以从底部开始执行实例化 .这意味着
tuple
的每个模板参数都需要15个额外的实例化级别来进行此检查 . 最重要的是,总是需要9个级别(恒定深度) .因此,17个参数要求实例化深度为17 * 15 9 == 264 .