Malachi
Malachi

Reputation: 2463

C++ non-type template template to function pointer/ref

Is something like this possible in C++11? I'd like to pass in as a non-type template parameter a templatized function pointer/ref:

template <template <typename ... TRest> void (*request_suffix)(ATCommander&, TRest...)>
struct command_helper
{
    template <class ...TArgs>
    static void request(ATCommander& atc, TArgs...args)
    {
        command_base::prefix(atc);
        request_suffix(atc, args...);
    }
};

Specifically, the usage of request_suffix? If so, is it possible also to dump the TArgs stuff?

I plan to then do something like:

// dummy example code, but very closely representative of the kind
// of thing we'll be doing
void specific_request_suffix(ATCommander& atc, const char* p1, int p2)
{
    cout << p1;
    cout << p2;
}

typedef command_helper<specific_request_suffix> command;

command::request(atc, "test param1", 7); // or similar

It's important that by the time command::request is issued, specific reference of specific_request_suffix should not be required. Also, I am in an embedded environment so std::function is not necessarily available

Upvotes: 1

Views: 289

Answers (1)

evpo
evpo

Reputation: 2531

I used decltype to infer types. It looks like a hack but surprisingly it works. See the implementation below:

void specific_request_suffix(ATCommander& atc, const char* p1, int p2)
{
    cout << p1;
    cout << p2;
}

template<typename T, T *t, typename... Args>
    struct command_helper
    {
        static T *func_ptr;
        static void Request(ATCommander &cmd, Args... args)
        {
            func_ptr(cmd, args...);
        }
    };

template<typename T, T *t, typename... Args>
    T *command_helper<T, t, Args...>::func_ptr = t;

template<typename T, T *t, typename... Args>
    command_helper<T, t, Args...> infer_command_helper(void(*f)(ATCommander&, Args...)) {}

template<typename T, T *t>
    struct command_type
    {
        using type = decltype(infer_command_helper<T, t>(t));
    };

using command = command_type<decltype(specific_request_suffix), specific_request_suffix>::type;

void Task()
{
    ATCommander cmd = 5;
    command::Request(cmd, "h", 10);
    cout << endl;
}

Note that the function name has to be used twice in the command type using declaration. I don't know how to avoid it :(

This answer says that it's not possible to infer type from non-type template parameter:

Since you are asking about a pure class template-based solution without the help of macro definitions then the answer is simple: as for now (Dec 2014, C++14) it is not possible.

This issue has been already identified by the WG21 C++ Standard Committee as a need and there are several proposals to let templates automatically infer the type of non-type template arguments.

Since we require to get the function type from the function pointer to simplify the command declaration, I am inclined to conclude that it's not possible until next language standards.

Previous attempt

This was my first attempt, but it didn't satisfy all the requirements. Leave it here in case it's useful to somebody.

template <typename... Rest>
struct command_helper
{
    using TFunc = std::function<void(ATCommander&, Rest...)>;

    static void request(ATCommander &cmd, TFunc func, Rest... rest)
    {
        func(cmd, rest...);
        cout << "Hello in template " << endl;
    }
};

Now you can use it as below:

using ATCommander = int;

auto f=[](ATCommander& cmd, int version, double d)
{
    cout << "In lambda " << cmd << " version " << version << " d= " << d;
};

ATCommander cmd = 5;
command_helper<int, double>::request(cmd, f, 1, 0.5);

Upvotes: 2

Related Questions