I'm trying to provide a wrapper around std::invoke to do the work of deducing the function type even when the function is overloaded.
(I asked a related question yesterday for the variadic and method pointer version).
When the function has one argument this code (C++17) works as expected under normal overload conditions:
#include <functional>
template <typename ReturnType, typename ... Args>
using FunctionType = ReturnType (*)(Args...);
template <typename S, typename T>
auto Invoke (FunctionType<S, T> func, T arg)
{
return std::invoke(func, arg);
}
template <typename S, typename T>
auto Invoke (FunctionType<S, T&> func, T & arg)
{
return std::invoke(func, arg);
}
template <typename S, typename T>
auto Invoke (FunctionType<S, const T&> func, const T & arg)
{
return std::invoke(func, arg);
}
template <typename S, typename T>
auto Invoke (FunctionType<S, T&&> func, T && arg)
{
return std::invoke(func, std::move(arg));
}
Reducing the code bloat is obviously needed for more input arguments, but that's a separate problem.
If the user has overloads differing only by const/references, like so:
#include <iostream>
void Foo (int &)
{
std::cout << "(int &)" << std::endl;
}
void Foo (const int &)
{
std::cout << "(const int &)" << std::endl;
}
void Foo (int &&)
{
std::cout << "(int &&)" << std::endl;
}
int main()
{
int num;
Foo(num);
Invoke(&Foo, num);
std::cout << std::endl;
Foo(0);
Invoke(&Foo, 0);
}
Then Invoke deduces the function incorrectly, with g++ output:
(int &)
(const int &)(int &&)
(const int &)
And clang++:
(int &)
(const int &)(int &&)
(int &&)
(Thanks to geza for pointing out that clang's outputs were different).
So Invoke has undefined behaviour.
I suspect that metaprogramming would be the way to approach this problem. Regardless, is it possible to handle the type deduction correctly at the Invoke site?