MaPo
MaPo

Reputation: 781

C++ template function pointer type deduction

I have the following code

using my_map_t = std::map<int, Object<double>>;
using my_map_iterator_t = my_map_t::iterator;


template <typename FWD, typename Func>
void inner(my_map_t& map, int key, FWD&& obj, Func emplacer) {
        emplacer(map, key, std::forward<FWD>(obj));
}
  

my_map_t map;

template <typename FWD>
void outer(my_map_t& map, int key, FWD&& obj)
{
        auto lambda = [](my_map_t& m, int k, FWD&& o) {
                m.emplace(k, std::forward<FWD>(o));
        };

        inner(map, key, std::forward<FWD>(obj), lambda);
}

which compiles painlessly. So this means that he deduce automatically the template argument of inner function. However, if I introduce a function pointer I need to specify the function pointer template argument, otherwise the compiler complaints

using my_map_t = std::map<int, Object<double>>;
using my_map_iterator_t = my_map_t::iterator;


template <typename FWD, typename Func>
void inner(my_map_t& map, int key, FWD&& obj, Func emplacer) {
        emplacer(map, key, std::forward<FWD>(obj));
}

template <typename FWD, typename Func>
void(*fp)(my_map_t&, int, FWD&&, Func) = &inner;


my_map_t map;

template <typename FWD>
void outer(my_map_t& map, int key, FWD&& obj)
{
        auto lambda = [](my_map_t& m, int k, FWD&& o) {
                m.emplace(k, std::forward<FWD>(o));
        };

        (*fp<FWD, decltype(lambda)>)(map, key, std::forward<FWD>(obj), lambda);
}

Why in the case of function pointer the argument deduction is not working any more? Did I make some mistake? Is there a way to achieve a better syntax?

NOTE ADDED

I need to use function pointer because I have some function with the same signature of inner. Let us call them inner1, inner2 and inner3. They are called by some outer function

void outer(...) {
     if(...) {

         inner1(...)
     } else if (...) {
     
         inner2(...)
     } else {

         inner3(...)
     }
     some_long_task(...)
}

Now in my case the outer function is called cyclically. The checks in the ifs can be time consuming and they are independent of the argument of outer function. I was thinking while the some_long_task is being executed, to set up a function pointer to the right function inner1, inner2 or inner3 exploiting some cpu parallelism, so that, the the new cycle begin, I do not have to waste time doing the if check.

Upvotes: 0

Views: 481

Answers (1)

NathanOliver
NathanOliver

Reputation: 180630

template <typename FWD, typename Func>
void(*fp)(my_map_t&, int, FWD&&, Func) = &inner;

is not a normal function pointer. It is what's called a variable template. When you have a variable template, in order to refer to a specific instantiation, you must specify the template parameters. To demonstratre that, consider

template <typename T>
constexpr T pi = T(3.1415926535897932385L);  

You can't just do cout << pi because we don't know which pi to use. The same occurs with

(*fp<FWD, decltype(lambda)>)(map, key, std::forward<FWD>(obj), lambda);

Here fp needs the <FWD, decltype(lambda)> so the compiler can know which specific fp instance to refer to. It has to do this even before it evaluates the function call because it needs to check the parameters against the function.

What we would need to not have to specify the parameter is a future like CTAD but would work for function pointer variable temapltes.

Upvotes: 3

Related Questions