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