In theory your hypothetical function apply
would look quite simple as a template
#include <iostream>
#include <type_traits>
struct C
{
C(int){};
};
template <class F, class... Args>
auto apply ( F&& f, Args&&... args) -> typename std::result_of<F(Args...)>::type
{
return f(args...);
}
float foo (int a, float b) { return a*b; }
int main()
{
auto b = apply(&foo, 3, 5.f);
//auto b = apply(&C::C, 3); //error: taking address of constructor 'C::C'
return 0;
}
But it is impossible to take address of constructor, as per the ISO standard. In most cases this special function is a non-entity in resulting code.
Neither explicit call to constructor is allowed. Your lambda function does thing differently. It constructs an object of class C
as to per defined effect of that expression.
You could use a bogus argument and SFINAE
template <class F, class... Args>
auto apply ( F&& f, Args&&... args)
-> std::enable_if_t<std::is_invocable<F, Args...>::value,
typename std::result_of<F(Args...)>::type>
{
return f(args...);
}
template <class T, class... Args>
auto apply ( T&&, Args&&... args)
-> std::enable_if_t<!std::is_invocable<T, Args...>::value,T&&>
{
return std::move(T(args...));
}
but it's preferable to avoid that and rethink whatever meta-programming pattern you have in mind, i.e. avoid attempt to call same template name for different kinds of arguments, or make amends with lambda use. E.g. you may avoid to call apply()
by using SFINAE.