Why can't decltype work with overloaded functions?

To figure out the type of the function from the type of the arguments you'd pass, you can "build" the return type by using decltype and "calling" it with those types, and then add on the parameter list to piece the entire type together.

template<typename... Ts>
using TestType = decltype(test(std::declval<Ts>()...))(Ts...);

Doing TestType<double, double> will result in the type int(double, double). You can find a full example here.

Alternatively, you might find the trailing return type syntax more readable:

template<typename... Ts>
using TestType = auto(Ts...) -> decltype(test(std::declval<Ts>()...));