做变体模板参数始终是最后? [英] Do Variadic Template Parameters Always Have to be Last?
问题描述
我总是必须在模板参数的末尾放置可变参数模板参数吗?
Do I always have to place variadic template parameters at the end of my template parameters?
template <size_t begin = 0U, typename... Tp>
void foo(tuple<Tp...> t);
例如,我遇到各种错误:
For example I get all kinds of errors with this:
#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);
}
当 run on 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);
b $ b prog.cpp:8:43:note:candidate: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:note:template argument deduction /替换失败:
prog.cpp:13:42:note:candidate: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:note:template argument deduction /替换失败:
prog.cpp: In instantiation of
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: required from here
prog.cpp:15:23: error: no matching function for call tofoo(std::tuple<int, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, float>&)
foo<Tp..., begin + 1>(t);
prog.cpp:8:43: note: candidate: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: note: template argument deduction/substitution failed:
prog.cpp:13:42: note: candidate: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: note: template argument deduction/substitution failed:
当参数换成:
template <size_t begin = 0U, typename... Tp>
void foo(tuple<Tp...> t);
程序正确运行: http://ideone.com/SozUbb
如果这真的要求可变参数模板参数是最后一次,有人可以给我一个来源的这个信息?
If this is really a requirement that variadic template parameters be last can someone give me a source on this information?
推荐答案
你错了 - 变量参数不一定是最后 -
You are wrong -- variardic arguments doesn't have to be last -- but it doesn't help you.
您的错误是在递归调用中,当您尝试将开始
设置为不同的 0
。在该行中,编译器无法确定您的 begin
应该是 std :: size_t
参数,
Your error is in the recursive call, when you try to set begin
to be something different than 0
. In that line, the compiler cannot figure out that your begin
is supposed to be the std::size_t
parameter, and bails out.
即使在gcc 5.1中也编译良好:
This compiles fine even in 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';
}
(我重写了它找出它在哪里出错,
(I rewrote it to figure out where it was going wrong, so it is slightly different in unimportant ways).
它的不同之处在于缺少递归调用的重要方式。
The important way it differs it the lack of recursive call.
一边,你的打印代码有点尴尬。请考虑使用 for_each_arg
:
As an aside, your printing code is a bit awkward. Consider using something like 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)
);
}
现在你没有递归深度等于元素数量
and now you don't have a recursion depth equal to the number of elements in your 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';
}
实例。
这篇关于做变体模板参数始终是最后?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!