SFINAE和重载函数的地址

Que*_*tin 12 c++ overloading sfinae template-argument-deduction c++17

我正在尝试bar在另一个函数的参数(foo1/ foo2)的上下文中解析重载函数()的地址.

struct Baz {};

int bar() { return 0; }
float bar(int) { return 0.0f; }
void bar(Baz *) {}

void foo1(void (&)(Baz *)) {}

template <class T, class D>
auto foo2(D *d) -> void_t<decltype(d(std::declval<T*>()))> {}

int main() {
    foo1(bar);      // Works
    foo2<Baz>(bar); // Fails
}
Run Code Online (Sandbox Code Playgroud)

没有问题foo1,bar明确指定了类型.

但是,foo2除了一个版本之外,通过SFINAE禁用自身bar,无法使用以下消息进行编译:

main.cpp:19:5: fatal error: no matching function for call to 'foo2'
    foo2<Baz>(bar); // Fails
    ^~~~~~~~~
main.cpp:15:6: note: candidate template ignored: couldn't infer template argument 'D'
auto foo2(D *d) -> void_t<decltype(d(std::declval<T*>()))> {}
     ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

据我所知,C++无法同时解析重载函数的地址并执行模板参数推导.

这是原因吗?有没有办法制作foo2<Baz>(bar);(或类似的东西)编译?

Myk*_*iuk 1

某种一般的答案在这里:Expression SFINAE to override on type of Passed Function Pointer

对于实际情况,不需要使用类型特征,或者decltype()- 好的旧重载解析将为您选择最合适的函数并将其分解为“参数”和“返回类型”。只需枚举所有可能的调用约定

// Common functions
template <class T, typename R> void foo2(R(*)(T*)) {}

// Different calling conventions
#ifdef _W64
template <class T, typename R> void foo2(R(__vectorcall *)(T*)) {}
#else
template <class T, typename R> void foo2(R(__stdcall *)(T*)) {}
#endif

// Lambdas
template <class T, class D>
auto foo2(const D &d) -> void_t<decltype(d(std::declval<T*>()))> {}
Run Code Online (Sandbox Code Playgroud)

将它们包装在模板化结构中可能会很有用

template<typename... T>
struct Foo2 {
    // Common functions
    template <typename R> static void foo2(R(*)(T*...)) {}
    ...
};
Zoo2<Baz>::foo2(bar);
Run Code Online (Sandbox Code Playgroud)

尽管如此,成员函数需要更多代码,因为它们具有修饰符 ( const, volatile, &&)