Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to return void from std::tuple_element if index is out of range?

I have a function traits struct that provides the types of a function's arguments using std::tuple_element:

#include <iostream>
#include <tuple>
#include <typeinfo>

template <typename T>
struct function_traits;

template <typename T_Ret, typename ...T_Args>
struct function_traits<T_Ret(T_Args...)> {
    // Number of arguments.
    enum { arity = sizeof...(T_Args) };
    // Argument types.
    template <size_t i>
    struct args {
        using type
            = typename std::tuple_element<i, std::tuple<T_Args...>>::type;
    };
};

int main() {
    using Arg0 = function_traits<int(float)>::args<0>::type;
    //using Arg1 = function_traits<int(float)>::args<1>::type; // Error, should be void.

    std::cout << typeid(Arg0).name() << std::endl;
    //std::cout << typeid(Arg1).name() << std::endl;
}

Working example: Ideone

If the index i is out of range (>= arity), this gives a compile-time error. Instead, I would like args<i>::type to be void for any i out of range.

While I can specialize args for specific i, such as i == arity, how could I go about specializing args for all i >= arity?

like image 938
zennehoy Avatar asked Sep 09 '16 07:09

zennehoy


1 Answers

With std::conditional and extra indirection:

struct void_type { using type = void; };


template <typename T_Ret, typename ...T_Args>
struct function_traits<T_Ret(T_Args...)> {
    // Number of arguments.
    enum { arity = sizeof...(T_Args) };

    // Argument types.
    template <size_t i>
    struct args {
        using type
            = typename std::conditional<(i < sizeof...(T_Args)),
                                        std::tuple_element<i, std::tuple<T_Args...>>,
                                        void_type>::type::type;
    };
};

Demo

like image 84
Jarod42 Avatar answered Sep 28 '22 19:09

Jarod42