Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the purpose of _t aliases and _v variable templates for type traits?

There are a lot of *_v and *_t suffixes, like std::is_same_v, std::invoke_result_t, result_of_t and milions of other such functions.

Why do they exist at all? Is it beneficial in any context to expose implementation details like std::result_of::type or std::is_same::value? Ignoring standard compliance, should the _v _t versions always be preferred? Could the ::type ::value versions have never existed at all?

like image 755
KamilCuk Avatar asked Nov 25 '25 12:11

KamilCuk


1 Answers

TL;DR - _t aliases can shorten metaprogramming code significantly due to omitting ::type and typename. _v variable templates were added later for symmetry with _t aliases and because they're just better in every way.

C++17 - _v variable templates

Here's a quote from proposal paper that introduced _v variable templates into C++17:

Variable templates like is_same_v<T, U> are superior to nested constants like is_same<T, U>::value for several reasons:

  1. Obviously, the former is 5 characters shorter.

  2. Less obviously, the former eliminates "disconnected verbosity". When working with type traits, it's common to have to say things like enable_if_t<!is_same<X, decay_t>::value, Z>, where "is_same" and "::value" are separated by a potentially substantial amount of machinery.

  3. Having to say "::value" isn't a feature, it's a workaround for a language limitation that has been solved. (Note that this proposal doesn't touch the struct templates, so metaprogrammers who want the is_same type instead of its nested constant are unaffected.)

Also, important points from the adoption paper:

Following the success of the _t alias templates for type traits, a matching set of _v variable templates have been proposed. The language support for variable templates arrived too late to confidently make this change for C++14, but experience since has shown that such variable templates are more succinct, can clean up the text in a similar way that the _t aliases have been widely adopted through the standard, and the author's experience using them in his own implementation of the standard type traits library is that code is much simpler when written using such variable templates directly, rather than turning a value into a type, then performing template manipulations on the type, before turning the type back into a value.
The impact on the standard is that many places that reference some_trait<T>::value would instead use some_trait_v<T>. The saving is not quite as great as in the case of alias templates, as there is no irksome typename to remove. However, the consistecy of using _t and _v to refer to traits, and not using ::something to extract meaning is compelling.

C++14 - _t aliases

Similar reasoning was provided in paper that introduced _t aliases in C++14, with the extra benefit of adding typename, which NathanOliver remarked in his answer. Quote from the paper:

Unfortunately, the above-described flexibility comes with a cost for the most common use cases. In a template context, C++ requires that each “metacall” to a metafunction bear syntactic overhead in the form of an introductory typename keyword, as well as the suffixed ::type:

typename metafunction-name<metafunction-argument(s)>::type

Even relatively straightforward compositions can rather quickly become somewhat messy; deeper nesting is downright unwieldy:

template< class T > using reference_t
   = typename conditional<is_reference<T>::value, T,
                          typename add_lvalue_reference<T>::type>::type;

Worse, accidentally omitting the keyword can lead to diagnostics that are arcane to programmers who are inexpert in metaprogramming details.

In our experience, passing metafunctions (rather than metadata) constitutes a relatively small fraction of metafunction compositions. We find ourselves passing metafunction results far more frequently. We therefore propose to add a set of template aliases for the library’s TransformationTraits in order to reduce the programmer burden of expressing this far more common case. Note, in the following rewrite of the above example, the absence of any typename keyword, as well as the absence of any ::type suffix, thus condensing the statement from 3 to 2 lines of code:

template< class T > using reference_t
    = conditional_t< is_reference<T>::value, T, add_lvalue_reference_t<T> >;
like image 139
Yksisarvinen Avatar answered Nov 27 '25 01:11

Yksisarvinen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!