1

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

Malachi
  • 2,260
  • 3
  • 27
  • 40
  • There ain't no such thing as a non-type template parameter. You could have a class template with a single (non-template) static method instead. – Igor Tandetnik Mar 24 '17 at 04:06
  • @IgorTandetnik please refer to http://en.cppreference.com/w/cpp/language/template_parameters – Malachi Mar 24 '17 at 05:21
  • I meant non-type template template parameter (the kind you try to make `request_suffix`) - there is indeed no such thing. You can pass a function pointer as a template parameter, but you can't pass a whole family of them. You can however pass a class (as a type parameter) that could have a member function template; or a class template (as a template template parameter) that could have a member function. Either of these achieve a goal of passing a family of functions to a template. – Igor Tandetnik Mar 24 '17 at 13:20

1 Answers1

2

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);
Community
  • 1
  • 1
evpo
  • 2,436
  • 16
  • 23
  • Clever, but as you predicted I don't think it covers my use case. I've updated my original post, and I will experiment with your solution – Malachi Mar 24 '17 at 05:26
  • What type is `specific_request_suffix` in your example? What type can it be? – evpo Mar 24 '17 at 05:32
  • Let me know what you think about the `decltype` solution. – evpo Mar 24 '17 at 11:16
  • Gonna try it out, it certainly is a solution but a little more verbose than I was hoping for . I'm gonna hold out for a magic bullet, but if none arrives this will be the accepted answer – Malachi Mar 24 '17 at 18:15
  • I updated the answer with a link to another question and a quote. It does not seem possible to simplify the command type declaration further :( – evpo Mar 25 '17 at 11:12
  • Yeah, it seems C++17 'auto' can help in this situation, but for C++11 (and appears C++14) we're kinda stuck – Malachi Mar 25 '17 at 22:13