Home > Enterprise >  Is exists SFINAE technique to check several statement?
Is exists SFINAE technique to check several statement?

Time:05-01

I want to check some prerequisite before invoke some function using SFINAE, example:

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

i try to do check: is return type of Fn is bool if Fn is accept one argument OR zero argument?

This code doesn't compile because happens substitution failure in enabled_if_t in example, but i want to somehow invoke checkBoolConstFn if at least one of statement:

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

or

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

is compile. Is exists some technique how to do it?

CodePudding user response:

Something like this, perhaps:

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

CodePudding user response:

It seems like what you need is is_invocable_r_v, i.e., we can just determine whether Fn can be invoked with the zero argument or one argument of type const T& to yield a result that is convertible to 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

  • Related