Search code examples
c++templatesc++17sfinae

Is exists SFINAE technique to check several statement?


In C++17, 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?


Solution

  • 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