是否存在SFINAE技术来检查几个语句?



在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) {}
};

演示

最新更新