In C++17, we have std::void_t
, which makes SFINAE look a lot nicer:
template <typename T>
std::void_t<decltype(T::prop)> foo() { /* stuff */ }
The template function will exist only if T::prop
exists.
If T::prop
exists, the template function foo()
would be equivalent to this:
template <typename T>
void foo() { /* stuff */ }
Otherwise, the code is equivalent to not declaring foo()
at all.
Is there any generalization of std::void_t
for other types in the standard library, such as the following:
template<typename T, typename...>
using generic_t = T;
so that the code below would be valid?
template <typename T>
std::generic_t<int, decltype(T::prop)> foo() { /* stuff */ }
which would be equivalent to
template <typename T>
int foo() { /* stuff */ }
if T::prop
exists?
void_t is a meta-function that maps any (number of) types to type void. The primary purpose of void_t is to facilitate writing of type traits. std::void_t will be part of C++17, but until then, it is extremely straightforward to implement: template <class...> using void_t = void;
The primary application of void_t is writing type traits that check validity of a statement. For example, let's check if a type has a member function foo () that takes no arguments: How does this work?
Converting a subclass type into a superclass type is called ‘ Generalization ‘ because we are making the subclass to become more general and its scope is widening. This is also called widening or up casting. Widening is safe because the classes will become more general.
Thus Java compiler will not ask for cast operator in generalization. So, in widening or Generalization, we can access all the superclass methods, but not the subclass methods. Converting a super class type into a sub class type is called ‘ Specialization ‘.
Why do you need such a generalization? void_t
is a little special in that it helps you easily write type traits, because you can have a primary with some type defaulted to void
and a specialization which uses void_t
. For instance:
template <class T, class = void>
struct has_prop : std::false_type { };
template <class T>
struct has_prop<T, std::void_t<decltype(T::prop)>> : std::true_type { };
It's not that there's anything special about void
, you just need some agreed upon type between the primary and the specialization.
void_t
doesn't make much sense if you're just using it directly in SFINAE though. You could just stick the expression somewhere else:
template <typename T, class = decltype(T::prop)>
void foo() { /* stuff */ }
at which point the return type is totally separate from the condition you're checking anyway, so if you want int
:
template <typename T, class = decltype(T::prop)>
int foo() { /* stuff */ }
It probably does not exist. It is not linked in the documentation and therefore I doubt its existence. But you can build such type on your own:
template <class type, class... sfinae_expressions>
using generic_t = type;
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