Does anybody know how to make a C++ concept T
such that the function g
is only defined for arguments t
with type T
if there exist an overload of f
in B
that accepts an argument t
?
struct A1 {};
struct A2 {};
struct B {
void f(A1 a1) {}
};
void g(T t) {
B b;
b.f(t);
}
As an example, I want to define a to_string
for everything that std::stringstream
accepts, and define something like
std::string to_string(T t) {
std::stringstream ret;
ret << t;
return ret.str();
}
All examples on concepts deal with the easier case of requiring the existance of a function on a type, while in this case we want to check existance of a function on another type.
If you want to check if the type is streamable or not, you can have something like:
#include <iostream>
#include <concepts>
#include <sstream>
template <typename T>
concept Streamable = requires (T x, std::ostream &os) { os << x; };
struct Foo {};
struct Bar {};
std::ostream& operator<<(std::ostream& os, Foo const& obj) {
// write obj to stream
return os;
}
template <Streamable T>
std::string to_string(T t) {
std::stringstream ret;
ret << t;
return ret.str();
}
int main() {
Foo f;
Bar b;
to_string(f);
to_string(b); // error
return 0;
}
Demo
You can use two different type placeholders in a single concept, to require both the existence of a member function for an instance of one of the type placeholders, as well as the argument to said member function to match the type of another placeholder. E.g.:
#include <iostream>
template<typename T, typename U>
concept HasMemFnConstFoo = requires(const T t, const U u) {
t.foo(u);
};
template<typename U>
struct Bar {
template <typename T>
static void bar(const T& t)
{
if constexpr (HasMemFnConstFoo<T, U>) { t.foo(U{}); }
else { std::cout << "foo() not defined\n"; }
}
};
struct A1 {};
struct A2 {};
struct B1 {
void foo(const A1&) const { std::cout << "B1::foo()\n"; }
};
struct B2 {
void foo(const A1&) { std::cout << "B2::foo()\n"; }
};
struct B3 {
void foo(A1&) const { std::cout << "B3::foo()\n"; }
};
int main() {
Bar<A1>::bar(B1{}); // B1::foo()
Bar<A2>::bar(B1{}); // foo() not defined
Bar<A1>::bar(B2{}); // foo() not defined [note: method constness]
Bar<A2>::bar(B2{}); // foo() not defined
Bar<A1>::bar(B3{}); // foo() not defined [note: argument constness]
Bar<A2>::bar(B3{}); // foo() not defined
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With