Suppose types can have Foo
, Bar
, Baz
methods, and we have type traits to check it. E.g. for Foo
we have HasFoo
:
template <class Type>
constexpr bool DetectFoo (decltype (std::declval<Type> ().Foo ())*) { return true; }
template <class Type>
constexpr bool DetectFoo (...) { return false; }
template <class Type>
constexpr bool HasFoo = DetectFoo<Type> (nullptr);
Let's write a Wrapper<Type>
class template, that forwards the property of Type
having or not having these methods. For any Type
the following should be satisfied:
Wrapper<Type> w;
should compile, since we did not call the methods yet.w.X ();
should compile iffHasX<Type>
, forX
=Foo
,Bar
,Baz
.HasX<Wrapper<Type>> == HasX<Type>
should hold, forX
=Foo
,Bar
,Baz
.
To conditionally enable a method in Wrapper
there is a clear way in C++20:
template <class Type>
struct Wrapper {
void Foo ()
requires HasFoo<Type>;
};
But what to do in earlier C++ standards, without concepts? I have come up with the following idea (see live demo):
template <class Type>
struct Wrapper {
template <bool dummy = true, class = std::enable_if_t<HasFoo<Type> && dummy>>
void Foo ();
};
This answer says it is ill-formed, NDR, but I don't understand the explanation. Is this really ill-formed, NDR?