I have the following case
template<typename Class>
concept has_member = requires (Class t)
{
// How can I write only either of the following conditions be satisfied?
{t.isInterface() }->std::same_as<bool>;
// or
{t.canInterface() }->std::same_as<bool>;
// or
// ... more conditions!
};
struct A {
bool isInterface() const { return true; }
};
struct B {
bool canInterface() const { return true; }
};
void foo(const has_member auto& A_or_B)
{
// do something
}
int main() {
foo(A{}); // should work
foo(B{}); // should work
}
Like I mentioned in the comments, I would like to logically or the requirements (in a single concepts
), so that the class A and B can be passed to the doSomething().
As per my knowledge, the the current concept is checking all the requirements, that means a logical and. If I take it apart to different concepts everything works, but I would need more concepts to be written tosatify the intention.
Is it possoble to combne into one? something like pseudocode
template<typename Class>
concept has_member = requires (Class t)
{
{t.isInterface() }->std::same_as<bool> || {t.canInterface() }->std::same_as<bool>;
// ...
};
CodePudding user response:
Anytime you want to start building concepts, you should start with the point-of-use. That is, the place where you are going to use some template parameters for some purpose.
That means, you start with foo
. How does foo
"do something" with this interface? It can't be as simple as:
void foo(const has_member auto& A_or_B)
{
A_or_B.isInterface();
}
That will be a compile error for some of the has_member
objects. So you will need to do this:
void foo(const has_member auto& A_or_B)
{
if constexpr(<stuff>)
A_or_B.isInterface();
else
A_or_B.hasInterface();
}
Where <stuff>
is some compile-time conditional check to see which actual interface the object has. You could spell out the requires
clause, but that would be unnecessarily wordy. So just stick them in a concept:
template<typename T>
concept has_is_interface = requires (Class t)
{
{t.isInterface() }->std::same_as<bool>;
};
template<typename T>
concept has_can_interface = requires (Class t)
{
{t.canInterface() }->std::same_as<bool>;
};
And now, your question answers itself:
template<typename Class>
concept has_member =
(has_is_interface || has_can_interface) &&
requires (Class t)
{
// ... more conditions!
};
That having been said, this design is generally wrongheaded. The reason is that it puts a lot of verbosity at the point of use.
What you probably want is to have a few free functions which can call the appropriate member interface:
bool do_is_interface(has_is_interface auto const& is_if)
{
return is_if.is_interface();
}
bool do_is_interface(has_can_interface auto const& is_if)
{
return is_if.can_interface();
}
And then your concept looks like:
template<typename Class>
concept has_member =
requires (Class t)
{
{ do_is_interface(t) } -> std::same_as<bool>
// ... more conditions!
};
CodePudding user response:
Is it possoble to combine into one?
Yes, it is possible. You can write the conjunction of two requires
as follows:
template<typename Class>
concept has_member =
requires (Class t) { {t.isInterface() }->std::same_as<bool>; }
|| //---> like this
requires (Class t) { {t.canInterface() }->std::same_as<bool>;};
// ... more conditions!
CodePudding user response:
You can use the following concept form stolen from the standard
#include <concepts>
template<typename Class>
concept has_member = requires (Class t) {
requires (requires { { t.isInterface() } -> std::same_as<bool>; } ||
requires { { t.canInterface() } -> std::same_as<bool>; }
// add more functions
);
};
which allows us to add different member functions directly in the requires
-clause.