做变体模板参数始终是最后? [英] Do Variadic Template Parameters Always Have to be Last?

查看:171
本文介绍了做变体模板参数始终是最后?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我总是必须在模板参数的末尾放置可变参数模板参数吗?

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 to foo(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆