gpt4 book ai didi

c++ - 为什么这会超过最大递归模板深度?

转载 作者:IT老高 更新时间:2023-10-28 21:42:55 27 4
gpt4 key购买 nike

我一直在使用可变参数模板并注意到以下内容。

这很好用:

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);

最佳答案

问题不是make_tuple,而是libstdc++(gcc4.8.2)中tuple的move构造函数。

对于类模板,成员函数仅在使用时才被实例化。 noexcept 规范也有类似的延迟,参见例如CWG issue 1330 .

当从 make_tuple 初始化一个变量时,移动构造函数被实例化,即使它被省略(例如,检查它是否格式错误)。这就是为什么您会看到只定义一个tuple变量使用make_tuple之间的区别。

移动构造函数有一个条件noexcept,它是递归实现的。因此,对于每个模板参数,需要恒定数量的附加实例化。超过最大实例化深度时clang++的错误输出摘录:(振作起来,输入的文字墙)

/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:803:24: note: in instantiation of default argument for '__test, std::_Tuple_impl &&>' required here      static true_type __test(int);                       ^~~~~~~~~~~/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:803:24: note: while substituting deduced template arguments into function template '__test' [with _Tp = std::_Tuple_impl, _Arg = std::_Tuple_impl &&, $2 = ]      static true_type __test(int);                       ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:117:14: note: in instantiation of template class 'std::__is_direct_constructible_impl, std::_Tuple_impl &&>' requested here    : public conditional::type             ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:818:14: note: in instantiation of template class 'std::__and_ >, std::__is_direct_constructible_impl, std::_Tuple_impl &&> >' requested here    : public __and_,             ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:896:14: note: in instantiation of template class 'std::__is_direct_constructible_new_safe, std::_Tuple_impl &&>' requested here    : public conditional::value,             ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:904:39: note: in instantiation of template class 'std::__is_direct_constructible_new, std::_Tuple_impl &&>' requested here    : public integral_constant, std::_Tuple_impl &&>' requested here    : public __is_direct_constructible             ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:956:39: note: in instantiation of template class 'std::__is_constructible_impl, std::_Tuple_impl &&>' requested here    : public integral_constant, std::_Tuple_impl &&>' requested here    : public conditional::type                         ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:1042:14: note: in instantiation of template class 'std::__and_, std::_Tuple_impl &&>, std::__is_nt_constructible_impl, std::_Tuple_impl &&> >' requested here    : public __and_,             ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:1073:14: note: in instantiation of template class 'std::is_nothrow_constructible, std::_Tuple_impl &&>' requested here    : public is_nothrow_constructible             ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:1079:14: note: in instantiation of template class 'std::__is_nothrow_move_constructible_impl, false>' requested here    : public __is_nothrow_move_constructible_impl             ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:117:14: note: in instantiation of template class 'std::is_nothrow_move_constructible >' requested here    : public conditional::type             ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/tuple:268:16: note: in instantiation of template class 'std::__and_, std::is_nothrow_move_constructible > >' requested here      noexcept(__and_,               ^/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8/type_traits:802:24: note: in instantiation of exception specification for '_Tuple_impl' requested here             = decltype(::new _Tp(declval()))>

我们可以在这里看到实现,例如is_nothrow_move_constructibleis_nothrow_constructible 的形式实现,以 __is_nt_constructible 等形式实现,共 15 个实例化级别。这就像调用堆栈一样打印,因此您可以从底部开始跟踪实例化。


这意味着 tuple 的每个模板参数都需要 15 个额外的实例化级别来进行此检查。最重要的是,始终需要 9 个级别(恒定深度)。

因此,17 个参数需要 17*15+9 == 264 的实例化深度。

关于c++ - 为什么这会超过最大递归模板深度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23374953/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com