2

I have problem with implementing recursive template (function in template struct), which will be terminated by std::tuple_size.

Here is fragment of code (I simplified code, to emphasize problem):

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);
        }

Initial template call looks like this:

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

GCC fails with error:

error: template argument ‘std::tuple_size::value’ involves template parameter(s) struct Helper::value, T_arguments...>

std::tuple_size is claimed to be known at compile time, so why I cannot use it template specialization?

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Goofy
  • 5,187
  • 5
  • 40
  • 56
  • Could you provide a simple example with no missing element? (Here for example, we cannot try it because `::value_size` is missing). – Morwenn Nov 11 '13 at 11:47
  • you may look at for an [explanation of the error](http://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol) and for a [solution](http://stackoverflow.com/questions/1198260/iterate-over-tuple) – Jarod42 Nov 11 '13 at 12:11
  • Note also that your implementation is buggy as you access out of bound of `tuple` in your specialization. – Jarod42 Nov 11 '13 at 12:18
  • @Jarod42 can you extend what's buggy? I'm new to C++ templates – Goofy Nov 11 '13 at 18:32
  • `std::get>::value> (arguments)` is an error equivalent to `char a[42]; a[42] = 0`, index should be in `[0; std::tuple_size[` (or `[0; std::tuple_size - 1]`). Note also the missing `std::tuple` in `tuple_size`. – Jarod42 Nov 11 '13 at 18:40

2 Answers2

1

Actually what you're doing is forbidden by section §14.5.4/9 which says,

A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.

Following may help:

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);
  }
Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

Use index_sequence and 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);
}
Khurshid Normuradov
  • 1,564
  • 1
  • 13
  • 20