在c++ 17中,我想在使用SFINAE调用某些函数之前检查一些先决条件,例如:
class TestClass
{
public:
bool foo() const { return true; }
bool bar() { return false; }
};
template<typename T>
class Checker
{
public:
template<typename Fn, typename = std::enable_if_t<(std::is_same_v<invoke_result_t<Fn, const T&>, bool>
|| std::is_same_v<invoke_result_t<Fn>, bool>)>>
void checkBoolConstFn(Fn fn) {}
};
int main()
{
auto foo = [](const TestClass&) { return true; };
auto bar = []() { return true; };
Checker<TestClass> checker;
checker.checkBoolConstFn(foo);
checker.checkBoolConstFn(bar);
checker.checkBoolConstFn(&TestClass::foo);
checker.checkBoolConstFn(&TestClass::bar);
return 0;
}
我试着做检查:是Fn的返回类型是bool如果Fn是接受一个参数或零参数?
这段代码不能编译,因为在示例中enabled_if_t中发生替换失败,但我想以某种方式调用checkBoolConstFn,如果至少有一个语句:
std::is_same_v<invoke_result_t<Fn, const T&>, bool>
或
std::is_same_v<invoke_result_t<Fn>, bool>
是编译。有什么技巧可以做到吗?
看起来您需要的是is_invocable_r_v
,也就是说,我们可以确定Fn
是否可以用const T&
类型的零参数或一个参数调用,以产生可转换为bool
的结果
template<typename T>
class Checker
{
public:
template<typename Fn,
typename = std::enable_if_t<
(std::is_invocable_r_v<bool, Fn, const T&> ||
std::is_invocable_r_v<bool, Fn>)>>
void checkBoolConstFn(Fn fn) {}
};
演示可能是这样的:
template<typename T>
class Checker
{
public:
template <typename Fn, typename = void>
struct InvocableWithT : public std::false_type {};
template <typename Fn>
struct InvocableWithT<
Fn,
std::enable_if_t<std::is_same_v<std::invoke_result_t<Fn, const T&>, bool>>>
: public std::true_type {};
template <typename Fn, typename = void>
struct InvocableWithNone : public std::false_type {};
template <typename Fn>
struct InvocableWithNone<
Fn,
std::enable_if_t<std::is_same_v<std::invoke_result_t<Fn>, bool>>>
: public std::true_type {};
template<
typename Fn,
typename = std::enable_if_t<
std::disjunction_v<InvocableWithT<Fn>, InvocableWithNone<Fn>>>>
void checkBoolConstFn(Fn fn) {}
};
演示