0

After reading the answers on how to get a parameter types of a function pointer and how to get the a return value of a function pointer (with cv-qualifier overloads), I decided to merge them into one function_traits class template:

#include <tuple>

using uint = unsigned int;

template <typename T>
struct function_traits;

template <typename R, typename ... Args>
struct function_traits<R(Args...)>
{
    using return_t = R;
    static const uint args_count = sizeof...(Args);

    template <uint i>
    struct arg
    {
        using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
    };
};

template <typename R, typename ... Args>
struct function_traits<R(*)(Args...)>
{
    using return_t = R;
    static const uint args_count = sizeof...(Args);

    template <uint i>
    struct arg
    {
        using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
    };
};

template <typename R, typename C, typename ... Args>
struct function_traits<R(C::*)(Args...)>
{
    using return_t = R;
    using class_t = C;
    static const uint args_count = sizeof...(Args);

    template <uint i>
    struct arg
    {
        using type = typename std::tuple_element<i, std::tuple<Args...>>::type;
    };
};

// cv-qualifier overloads ...

The code above works fine, but I also wanted to provide a few typedefs to spare me the typing. However, the compiler gives me error on the arg_t when I try to instantiate the nested class template arg with template parameter i. I'm not that skilled with templates so it's possibly a basic thing I'm missing here. What is it?

template <typename T>
using return_t = typename function_traits<T>::return_t;

template <typename T>
using class_t = typename function_traits<T>::class_t;

template <typename T, uint i>
using arg_t = typename function_traits<T>::arg<i>::type;
//                                            ^
//                                    ';' expected here

Here's the output from Coliru.

Community
  • 1
  • 1
LogicStuff
  • 19,397
  • 6
  • 54
  • 74

1 Answers1

2

Since arg<i> is a member of a template, you need to specify in the code that it is a template. You need to specify this because arg could be a template or not be a template depending on specializations of function_traits. Members of templates need to be specified if they are types or templates. You as the programmer need to tell the compiler that arg<i> is a template. You can do that by doing this:

template <typename T, uint i>
using arg_t = typename function_traits<T>::template arg<i>::type;

It looks weird, but that's the way C++ is.

JKor
  • 3,822
  • 3
  • 28
  • 36