Проблема заключается не в make_tuple
, а в конструкторе перемещения tuple
в libstdc ++ (gcc4.8.2).
Для шаблонов классов функции-члены генерируются только при использовании. Спецификация noexcept также откладывается аналогично, см., Например, Проблема CWG 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_constructible
в терминах is_nothrow_constructible
, который реализован в терминах __is_nt_constructible
и т. д., для 15 уровней инстанцирования. Это напечатано как стек вызовов, поэтому вы можете следить за экземплярами, начиная со дна.
Это означает, что для каждого аргумента шаблона для tuple
требуется 15 дополнительных уровней инстанцирования для этой проверки. Кроме того, всегда требуются 9 уровней (постоянная глубина).
Поэтому 17 аргументов требуют глубины создания 17 * 15 + 9 == 264.