Pre-C++14 type traits were written like this:
struct A {};
template <typename T> struct is_A : std::false_type {};
template <typename T> struct is_A<A<T>> : std::true_type {};
C++14 variable templates lets us spell them like this:
struct A {};
template <typename T> constexpr bool is_A = false;
template <typename T> constexpr bool is_A<A<T>> = true;
Things in <type_traits>
use the first form. Some newer stuff like borrowed_range<T>
uses the second form.
Is there any objective reason to prefer one or the other? Or are they equivalent for all purposes except brevity?
Is there any objective reason to prefer one or the other?
The first version is prefered if you want to be able to use your type trait in situations where a bool
won't work, like with certain other standard library type traits, such as std::conjunction
.
template<class T>
struct A {};
template <class T> struct is_A : std::false_type {};
template <class T> struct is_A<A<T>> : std::true_type {};
template <class T> inline constexpr bool is_A_v = is_A<T>::value;
template<class... Ts>
std::enable_if_t<std::conjunction_v<is_A<std::remove_cvref_t<Ts>>...>>
foo(Ts&&... args) {
//...
}
The first form lets you do things like this:
void foo(std::false_type);
void foo(std::true_type);
template <typename T>
void bar(const T& value) {
func(is_A<T>{});
}
But even that is a subjective benefit, because not everyone likes that style of code and you can achieve the same goals with if constexpr
or requires
, which makes sense because those are newer language features which evolved in the presence of C++14 variable templates.
So my answer is no, there's no objective benefit to one over the other in a general sense.
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