【问题标题】:Recursive variadic template terminated by std::tuple_size in C++11在 C++11 中由 std::tuple_size 终止的递归可变参数模板
【发布时间】:2013-11-11 09:12:20
【问题描述】:

我在实现递归模板(模板结构中的函数)时遇到问题,它将被 std::tuple_size 终止。

这是代码片段(我简化了代码,以强调问题):

template<int index, typename ...T_arguments>
    struct Helper
    {
        static void func (size_t&                           return_size,
                          const std::tuple<T_arguments...>& arguments)
        {
            const auto& argument (std::get<index> (arguments));

            return_size += ::value_size (argument);

            ::Helper<index + 1, T_arguments...>::func (return_size, arguments);
        }

// ...

template<typename... T_arguments>
    struct Helper<std::tuple_size<T_arguments...>::value, T_arguments...>
    {
        static void func (size_t&                           return_size,
                          const std::tuple<T_arguments...>& arguments)
        {
            const auto& argument (std::get<std::tuple_size<T_arguments...>::value> (arguments));

            return_size += ::value_size (argument);
        }

初始模板调用如下所示:

Helper<0, T_arguments...>::func (return_size, arguments);

GCC 失败并出现错误:

错误:模板参数‘std::tuple_size::value’ 涉及模板参数 struct Helper::value, T_arguments...>

std::tuple_size号称在编译时就知道了,为什么我不能用模板特化呢?

【问题讨论】:

  • 你能提供一个没有缺失元素的简单例子吗? (例如这里,我们无法尝试,因为缺少::value_size)。
  • 另请注意,您的实现是错误的,因为您在专业化中访问了tuple 的边界。
  • @Jarod42 你能扩展什么是错误的吗?我是 C++ 模板的新手
  • std::get&lt;std::tuple_size&lt;std::tuple&lt;T_arguments...&gt;&gt;::value&gt; (arguments) 是等同于char a[42]; a[42] = 0 的错误,索引应位于[0; std::tuple_size&lt;std::tuple&lt;T_arguments...&gt;[(或[0; std::tuple_size&lt;std::tuple&lt;T_arguments...&gt; - 1])中。还要注意tuple_size 中缺少的std::tuple

标签: c++ templates c++11 recursion


【解决方案1】:

实际上,第 14.5.4/9 节禁止您所做的事情,

部分特化的非类型实参表达式不应涉及部分特化的模板形参,除非实参表达式是简单标识符。

以下可能会有所帮助:

template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
  total_value_size(size_t& return_size, const std::tuple<Tp...>& t)
  { }

template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
  total_value_size(size_t& return_size, const std::tuple<Tp...>& t)
  {
        const auto& argument (std::get<I> (t));

        return_size += ::value_size(argument);
        total_value_size<I + 1, Tp...>(return_size, t);
  }

【讨论】:

    【解决方案2】:

    使用 index_sequence 和 range-based-for。

    #include <cstdlib>
    #include <cstddef>
    
    #include <tuple>
    
    namespace mpl
    {
        template< std::size_t ... I>
        struct index_sequence
        {
        };
    
        template< std::size_t s, typename I1, typename I2>
        struct concate;
    
        template< std::size_t s, std::size_t ...I, std::size_t ...J>
        struct concate<s, index_sequence<I...>, index_sequence<J...> >
        {
            typedef index_sequence<I... ,( J + s)... > type;
        };
    
    
        template< std::size_t N>
        struct make_index_sequence
        {
            typedef typename concate< N/2,
               typename make_index_sequence< N/2>::type,
               typename make_index_sequence< N - N/2>::type
            >::type type;
        };
    
        template<>struct make_index_sequence<0>
        {
            typedef index_sequence<> type;
        };
    
        template<> struct make_index_sequence<1>
        {
            typedef index_sequence<0> type;
        };
    
        template< typename ...T>
        struct index_sequence_for
        {
            typedef typename make_index_sequence< sizeof...(T) > ::type type;
        };
    } // mpl
    
    
    template< typename T >
    std::size_t value_size( T ){ return sizeof(T); }// only for illustration
    
    template< typename ...Tp, std::size_t ...i>
    std::size_t total_value_size_impl( const std::tuple<Tp...> & t, mpl::index_sequence<i...> )
    {
        std::size_t result=0;
    
        for(auto x: { value_size( std::get<i>(t) ) ... } )
        {
              result += x;
        }
    
        return result;
    
    }
    
    template< typename ...Tp>
    std::size_t total_value_size( const std::tuple<Tp...> & t)
    {
        typedef typename mpl::index_sequence_for<Tp...> :: type indexes;
    
        return total_value_size_impl( t, indexes{} );
    }
    
    #include <cstdio>
    
    int main()
    {
        typedef std::tuple<int, char, double> types;
    
        std::size_t result = total_value_size(types{});
    
        printf("%d\n", result);
    }
    

    【讨论】:

      猜你喜欢
      • 2018-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-19
      • 2017-02-23
      • 1970-01-01
      • 1970-01-01
      • 2012-05-13
      相关资源
      最近更新 更多