我正在使用宏来进行编译时签名匹配,如下所示:
#define ifSigMatch(sig) if constexpr (std::is_same_v<decltype(std::function{std::forward<Foo>(f)}), std::function<sig>>)
template <class T, class Foo> void afoo(Foo f) {
ifSigMatch(void(T)) { ... }
ifSigMatch(bool(T)) { ... }
ifSigMatch(bool(T, int)) { ... }
...
}
有没有办法处理
Foo
的第一个输入参数是任何指针类型的情况,或者参数可以隐式转换为T
,而不需要向afoo
添加更多模板参数?
最好是 c++17 或更低版本。
要处理
Foo
的第一个输入参数是任何指针类型或可隐式转换为 T
的情况,您可以将 SFINAE(替换失败不是错误)与 std::enable_if
结合使用。以下是您如何修改宏和模板函数afoo
以实现此目的,而无需添加更多模板参数:
#include <functional>
#include <type_traits>
#define ifSigMatch(sig) if constexpr (std::is_invocable_v<Foo, sig>)
template <class T, class Foo>
void afoo(Foo f) {
ifSigMatch(T*) { ... }
else ifSigMatch(std::enable_if_t<std::is_convertible_v<std::invoke_result_t<Foo, T>, T>, T>) { ... }
else ifSigMatch(bool(T)) { ... }
else ifSigMatch(bool(T, int)) { ... }
// Add more conditions as needed
// ...
}
您可以使用具有类模板专门化的辅助类来获取返回类型和参数类型,然后在 constexpr 方法中使用它们来比较签名。
如果您想允许返回类型可转换为您指定的类型,可以使用
std::is_convertible_v
代替 std::is_same_v
。
#include <type_traits>
template <typename>
struct Function; // This primary template is not defined.
template <typename R, typename... Args>
struct Function<R(Args...)> {
template <typename Foo>
constexpr bool matchesSig() {
if constexpr (std::is_invocable_v<Foo, Args...>) {
// only return true when the return type is EXACTLY as specified
// otherwise, ifSigMatch(bool(T)) would also always imply
// ifSigMatch(void(T)) to be true
return std::is_same_v<std::invoke_result_t<Foo, Args...>, R>;
}
return false;
};
};
#define ifSigMatch(sig) if constexpr (Function<sig>().template matchesSig<Foo>())