Recently I was using concept
s to define different constructors for a template
d struct
. Here is the code:
#include <iostream>
namespace detail {
template<typename T, typename U >
concept SameHelper = std::is_same_v<T, U>;
}
template<typename T, typename U >
concept same_as = detail::SameHelper<T, U> && detail::SameHelper<U, T>;
template<typename T>
concept trivial = same_as<T, bool> || same_as<T, char>;
template<typename T>
concept not_trivial = !trivial<T>;
template<typename T>
struct Foo
{
Foo(T t) requires trivial<T> : member{t} { std::cout << "Foo is trivial" <<std::endl; }
Foo(const auto& t) requires not_trivial<T> : member{t} { std::cout << "Foo is not trivial" <<std::endl;}
const T member;
};
template<typename T>
struct Bar
{
Bar(auto t) requires trivial<T> : member{t} { std::cout << "Bar is trivial" <<std::endl; }
Bar(const T& t) requires not_trivial<T> : member{t} { std::cout << "Bar is not trivial" <<std::endl;}
const T member;
};
template<typename T>
struct Baz
{
Baz(auto t) requires trivial<T> : member{t} { std::cout << "Baz is trivial" <<std::endl; }
Baz(const auto& t) requires not_trivial<T> : member{t} { std::cout << "Baz is not trivial" <<std::endl;}
const T member;
};
template<typename T>
struct Qux
{
Qux(T t) requires trivial<T> : member{t} { std::cout << "Qux is trivial" <<std::endl; }
Qux(const T& t) requires not_trivial<T> : member{t} { std::cout << "Qux is not trivial" <<std::endl;}
const T member;
};
int main()
{
Foo(true);
Foo(3.14159);
Bar(true);
Bar(3.14159);
//Baz(true); // does not compile if uncommented
//Baz(3.14159); // does not compile if uncommented
//Qux(true); // does not compile if uncommented
//Qux(3.14159); // does not compile if uncommented
return 0;
}
You can run the above code online. I am wondering why Foo and Bar compile fine, whereas Baz and Qux do not compile if uncommented. IMHO the syntax for Baz and Qux is mutch more convenient.