Danh Danh - 1 month ago 8
C++ Question

C++17, why doesn't auto non-type template parameter work with SFINAE

I'm attempting to solve this question.

In my below code, I want to use

FunctionInfo
to detect which overload of a function chosen by its parameter list.

With:

decltype(MethodInfo<Foo, int>::get(&Foo::foo))


I can choose correct overload function based on the parameter list.

I want to go 1 step further to be able to use:

FunctionInfo<Foo, std::tuple<int>, &Foo::foo>::type


But when I tried with the solution below, clang in HEAD 4.0.0 report this:

error: non-type template parameter 'f' with type 'auto' has incompatible
initializer of type '<overloaded function type>'
FunctionInfo<Foo, std::tuple<int>, &Foo::foo>::type
^~~~~~~~~


My question is why SFINAE doesn't involve to choose which function is suitable.

#include <type_traits>
#include <tuple>

template<typename T, typename... Args>
struct MethodInfo {
template<typename Ret>
static auto get(Ret(T::*)(Args...)) -> Ret(T::*)(Args...);
};

template<typename T, typename Tuple>
struct MethodInfoFromTuple;

template<typename T, typename...Args>
struct MethodInfoFromTuple<T, std::tuple<Args...>>{
using type = MethodInfo<T, Args...>;
};

template<typename T, typename ArgPack, auto f,
typename Func = decltype(MethodInfoFromTuple<T, ArgPack>::type::get(f))>
struct FunctionInfo {
using type = Func;
};

struct Foo {
int foo(int);
// Uncomment this line then only first static_assert work
// int foo(int, int);
};

int main() {
static_assert(std::is_same<
int(Foo::*)(int),
decltype(MethodInfo<Foo, int>::get(&Foo::foo))
>::value, "");
static_assert(std::is_same<
int (Foo::*)(int),
FunctionInfo<Foo, std::tuple<int>, &Foo::foo>::type
>::value, "");

}

Answer

Overload sets are not values in C++. Template non-type arguments are values.

Overload sets are resolved to values in a narrow set of circumstances, using specific rules, These rules are not "try each possibility and if there are more than one legal possibility, generate an error". Instead there are cases where exact matches are picked, and others where an ordering on the viable overloads is done and if there is no tie "the best" is picked.

The case where you pass to auto is neither.