I have a generic function which can accept types which have at least one of a list of member functions.
I am trying to write an inline requires expression to validate this.
I have an example below which fails to compile because neither of my types pass the requires clause
#include <iostream>
struct Foo
{
bool has_foo() const { return true; }
};
struct Bar
{
bool has_bar() const { return true; }
};
template<typename T>
bool check(const T& t)
requires requires (T t)
{
{ t.has_foo() || t.has_bar() };
}
{
if constexpr (requires { t.has_foo(); })
{
if (t.has_foo())
std::cout << "has foo\n";
else
std::cout << "no foo\n";
}
if constexpr (requires { t.has_bar(); })
{
if (t.has_bar())
std::cout << "has bar\n";
else
std::cout << "no bar\n";
}
return true;
}
int main()
{
check(Foo());
check(Bar());
return 0;
}
The build fails due to:
test.cpp:40:10: error: no matching function for call to 'check(Foo)'
40 | check(Foo());
| ~~~~~^~~~~~~
test.cpp:15:6: note: candidate: 'template<class T> bool check(const T&) requires requires(T t) {{t.has_foo() || t.has_bar()};}'
15 | bool check(const T& t)
| ^~~~~
test.cpp:15:6: note: template argument deduction/substitution failed:
test.cpp:15:6: note: constraints not satisfied
test.cpp: In substitution of 'template<class T> bool check(const T&) requires requires(T t) {{t.has_foo() || t.has_bar()};} [with T = Foo]':
test.cpp:40:10: required from here
test.cpp:15:6: required by the constraints of 'template<class T> bool check(const T&) requires requires(T t) {{t.has_foo() || t.has_bar()};}'
test.cpp:16:14: in requirements with 'T t' [with T = Foo]
test.cpp:18:23: note: the required expression '(t.has_foo() || t.has_bar())' is invalid, because
18 | { t.has_foo() || t.has_bar() };
| ~~~~~~~~~~~~^~~~~~~~~~~~~~
test.cpp:18:28: error: 'struct Foo' has no member named 'has_bar'
18 | { t.has_foo() || t.has_bar() };
| ~~^~~~~~~
How can I turn my requires expression
requires (T t)
{
{ t.has_foo() || t.has_bar() };
}
into a logical or expression, such that types which meet either of the expressions are allowed?
You can split it into two requires expressions, which can be combined with logical OR:
template<typename T>
bool check(const T& t)
requires(
requires (T t) { t.has_foo(); } ||
requires (T t) { t.has_bar(); }
)
{
// [...]
}
If that looks too convoluted, you can also define that as a new concept:
template<typename T>
concept has_foo_or_bar =
requires (T t) { t.has_foo(); } ||
requires (T t) { t.has_bar(); };
template<typename T>
bool check(const T& t)
requires( has_foo_or_bar<T>(t) )
{
// [...]
}