Вопрос

Lets say I have a variadic higher order function

template<typename F, typename ...Args>
void execution(F func, Args&&... args)
{
    func(std::forward<Args>(args)...);
}

Then for this overload set

void f() {}
void f(int arg) {}

Overload resolution will be impossible

int main()
{
    execution(f, 1);
    execution(f);
    return 0;
}

Yet if only either one of the two is provided, the program compiles

  1. Why does this happen ? Why template argument deduction fails?
  2. If I remove f() from the set and replace it with f(arg, arg2) there's still a problem. Is there a workaround, or do I always have to provide the type of the function as a template argument ?

    execution<void()>(f);
    
Это было полезно?

Решение 2

You need an overload set object. This is an object that represents the entire overload set of functions of f:

struct f_overload_set {
  template<typename...As>
  auto operator()(As&&...as)->
    decltype(f(std::declval<As>()...))
  { return f(std::forward<As>(as)...); }
};

now pass f_overload_set{} to your template function.

templates function value arguments must be values, and in current C++ there is no first class value that represents an entire overload set of a function. The symbol f gets disambiguated into one overload at each point of use: but that requires an immediate context at the point of use. The above defers the disambiguation until we have the arguments handy.

Другие советы

When doing template type deduction, the compiler doesn't analyse how the types are used inside the function. Therefore when deducing the template parameters, the compiler sees no relation between the different template arguments. Thus the additional variadic template arguments don't matter at all, and the problem can be reduced to

template<typename Func> void execution(Func func);

void f();
void f(int);

execution(f);

With this minimized code, it should be obvious why template argument deduction fails.

You can resolve this by making your first argument explicitly dependent on the remaining template arguments, e.g.:

template<typename... Args>
 void execution(void (*func)(Args ...), Args ... args)
{
  func(std::forward<Args>(args) ...);
}

There is no specific function 'f' available:

Simplifying it:

template<typename F>
void execution(F func)
{}

void f() {}
void f(int arg) {}

int main()
{
    execution(f);
    return 0;
}

You have two functions 'f' available for template parameter deduction/substitution

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top