可变参数模板参数始终必须是最后一个
Do Variadic Template Parameters Always Have to be Last?
我是否总是必须在模板参数的末尾放置可变参数模板参数?
template <size_t begin = 0U, typename... Tp>
void foo(tuple<Tp...> t);
例如,我收到各种错误:
#include <functional>
#include <iostream>
#include <string>
#include <tuple>
using namespace std;
template <typename... Tp, size_t begin = 0U>
enable_if_t<begin == sizeof...(Tp), void> foo(tuple<Tp...>& t){
cout << endl;
}
template <typename... Tp, size_t begin = 0U>
enable_if_t<begin < sizeof...(Tp), void> foo(tuple<Tp...>& t) {
cout << get<begin>(t) << ' ';
foo<Tp..., begin + 1>(t);
}
int main() {
tuple<int, string, float> t = make_tuple(42, "Jonathan Mee", 13.13);
foo(t);
}
在 gcc 5.1 上运行时,给我:
prog.cpp: 在实例化
std::enable_if_t<(begin < sizeof... (Tp)), void> foo(std::tuple<_Elements ...>&) [with Tp = {int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, float}; unsigned int begin = 0u; std::enable_if_t<(begin < sizeof... (Tp)), void> = void]
:
prog.cpp:21:7:从这里
需要 prog.cpp:15:23:错误:调用foo(std::tuple<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, float>&)
没有匹配函数foo<Tp..., begin + 1>(t);
进度.cpp:8:43:注:候选人:template<class ... Tp, unsigned int begin> std::enable_if_t<(begin == sizeof... (Tp)), void> foo(std::tuple<_Elements ...>&)
enable_if_t<begin == sizeof...(Tp), void> foo(tuple<Tp...>& t){
prog.cpp:8:43: 注意:模板参数推导/替换失败:
进度.cpp:13:42:注:候选人:template<class ... Tp, unsigned int begin> std::enable_if_t<(begin < sizeof... (Tp)), void> foo(std::tuple<_Elements ...>&)
enable_if_t<begin < sizeof...(Tp), void> foo(tuple<Tp...>& t) {
prog.cpp:13:42:注意:模板参数推导/替换失败:
当参数交换为:
template <size_t begin = 0U, typename... Tp>
void foo(tuple<Tp...> t);
程序运行正常:http://ideone.com/SozUbb
如果这真的是可变参数模板参数是最后一个的要求,有人可以给我一个关于这些信息的来源吗?
问题不在于模板声明。这完全没问题:
template <typename... Tp, size_t begin = 0U>
void foo(tuple<Tp...> t);
问题是这个调用:
foo<Tp..., begin + 1>(t);
虽然您可以在参数包后提供默认模板参数,但以后无法实际设置它。编译器无法知道包在哪里结束以及包开始后的参数。
您应该翻转顺序以将begin
作为第一个参数,默认为:
template <size_t begin = 0U, typename... Tp>
void foo(tuple<Tp...> t);
以便您的递归调用可以是:
foo<begin + 1>(t);
变量参数不一定是最后一个 - 但它对你没有帮助。
您的错误在于递归调用,当您尝试将begin
设置为与0
不同的内容时。 在这一行中,编译器无法确定您的begin
应该是std::size_t
参数,因此会纾困。
即使在 gcc 5.1 中也能很好地编译:
template <class... Tp, std::size_t begin = 0U>
auto foo(std::tuple<Tp...>& t) -> std::enable_if_t<begin == sizeof...(Tp), void> {
std::cout << 'n';
}
template <class... Tp, std::size_t begin = 0U>
auto foo(std::tuple<Tp...>& t) -> std::enable_if_t<begin < sizeof...(Tp), void> {
std::cout << 'n';
}
(我重写了它以找出它出错的地方,所以它在不重要的方面略有不同)。
它的重要区别在于缺少递归调用。
顺便说一句,您的打印代码有点尴尬。 考虑使用类似 for_each_arg
的内容:
template<class F, class...Args>
void for_each_arg(F&& f, Args&&...args) {
using discard=int[];
(void)discard{((
f(std::forward<Args>(args))
),void(),0)...,0};
}
要么将上述内容与std::apply
混合,要么编写自己的:
namespace details {
template<class F, class Tuple, std::size_t...Is>
decltype(auto) apply( std::index_sequence<Is...>, F&& f, Tuple&& args )
{
return std::forward<F>(f)( std::get<Is>(std::forward<Tuple>(args))... );
}
}
template<class F, class Tuple>
decltype(auto) apply(F&& f, Tuple&& tuple) {
using dTuple = std::decay_t<Tuple>;
return details::apply(
std::make_index_sequence<std::tuple_size<dTuple>::value>{},
std::forward<F>(f),
std::forward<Tuple>(tuple)
);
}
template<class F, class Tuple>
decltype(auto) for_each_tuple_element( F&& f, Tuple&& tuple ) {
return apply(
[&](auto&&...args){
for_each_arg( std::forward<F>(f), decltype(args)(args)... );
},
std::forward<Tuple>(tuple)
);
}
现在您的递归深度不等于元组中的元素数量。
template <class Tuple>
void foo(Tuple&& tuple) {
for_each_tuple_element(
[](auto&& arg){ std::cout << decltype(arg)(arg); },
std::forward<Tuple>(tuple)
);
std::cout << 'n';
}
活生生的例子。
根据标准 §14.1/11 模板参数 [temp.param]:
如果主类模板或别名模板的模板参数是模板参数包,则应为最后一个模板参数。函数模板的模板参数包后不得跟另一个模板参数,除非可以从参数类型列表中推导出该模板参数 函数模板或具有默认参数。
因此,您的设置是正确的,因为可变参数后跟默认模板参数。但是,您有一个语法错误,您应该更改为:
template <typename... Tp, size_t begin = 0U>
^^^^^^
void foo(tuple<Tp...> t);
也就是说,在模板参数列表中...
必须在Tp
之前。
- 更改可变参数模板中的最后一个类型
- 这种获取模板参数包中最后一个元素的方法是否有隐藏的开销?
- C++模板:无法匹配可变参数类模板中的最后一个模板
- 如何更改参数包中的最后一个参数
- 模板参数重载,最后一个参数为非类型名
- 有没有办法访问除最后一个模板参数之外的所有内容
- 此模板函数上的最后一个参数有什么用?
- 如何在参数包不是最后一个参数的C++中编写可变参数模板函数?
- C :为什么它总是首先执行最后一个参数
- std::transform的最后一个参数
- C++模板部分特化:为什么我无法匹配可变参数模板中的最后一个类型
- 默认参数模板与可变参数模板:最后一个模板参数是什么
- 将除最后一个作为变量类型的变量外的所有可变模板参数解包
- 可变参数模板参数始终必须是最后一个
- 基于最后一个参数值的构造函数
- 最后一个参数将覆盖 SQLite 绑定中的先前参数
- 函数模板的非最后一个默认模板参数
- 通过去掉最后一个参数,将c++中的for(a;b;c)简化为for(x;y;)
- 当可变参数模板不是最后一个参数时,如何重载它们
- 默认参数:只能保留最后一个参数