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

Is exists SFINAE technique to check several statement?

在 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 接受一个参数或零参数,return Fn 的类型是否为 bool?

此代码无法编译,因为在示例中 enabled_if_t 中发生替换失败,但我想以某种方式调用 checkBoolConstFn 如果至少有一个语句:

std::is_same_v<invoke_result_t<Fn, const T&>, bool>

std::is_same_v<invoke_result_t<Fn>, bool>

正在编译。是否存在一些技术如何做到这一点?

可能是这样的:

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

Demo

看来你需要的是is_invocable_r_v,也就是说,我们可以确定是否可以用零参数或const T&类型的一个参数调用Fn来产生一个可转换为 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) {}
};

Demo