° Preamble
This question is particularly related to the helper variable templates defined by/in the STL for all the types deriving from std::integral_constant.
° Context
I am in the process of writing a compile-time only library which aims to provide the most possible features of the STL (until C++17 for now), by using the least possible features of the language after C++11.
That is, everything that can be done using C++11 features only, are implemented using C++11. For things that cannot be implemented like that, the library will have to provide other options...
Side Note
The purpose is to minimize the needed modifications to the code, produced using the library, when this code has to be compiled with compilers having a reduced set of language features. Ie: Compilers of the 'embedded world' does often not provide everything one would them to be able to do.
° Chronology
C++11 standard library came up with std::integral_constant.
This 'helper class' was already defining the cast operator for value_type.
C++14 added the invoke operator to it, and this 'new' language feature 'variable template'.
C++17 added std::bool_constant though std::true_type and std::false_type were already defined from C++11 as std::integral_constant<bool, true and false > respectively.
C++17 also added inline variable template... There, suddenly, all the types deriving from std::integral_constant were all defining a 'helper' variable template.
Note
I perfectly understand what is the purpose of an inline variable template.
The question here is about the usefulness of the 'helpers' defined for the types deriving from std::integral_constant.
° A Bit Food
Now, consider the following code examples:
/* Test template using std::integral_constant<bool, false>
*/
template<typename...>
using AlwaysFalse = std::false_type;
/* Example #1
*/
template<typename T>
struct AssertAlwaysFalse {
static_assert(
AlwaysFalse<T>{},
"Instatiation and bool cast operator replaces variable template."
);
using Type = T;
};
using AlwaysFalseType = typename AssertAlwaysFalse<int>::Type;
/* Example #2
*/
constexpr auto alwaysFalseAuto = AlwaysFalse<int>{};
constexpr bool alwaysFalseBool = AlwaysFalse<int>{};
/* Example #3
*/
template<bool AlwaysF>
struct AlwaysFalseArg { static constexpr bool Result = AlwaysF; };
constexpr bool alwaysFalseArg = AlwaysFalseArg<AlwaysFalse<int>{}>::Result;
The above examples show that instantiating an std::integral_constant, where a value is expected, has the exact same effect one would obtain by using a 'helper' variable template.
This is perfectly natural. std::integral_constant defines the cast operator for value_type. This behavior is purely C++11, and was available way before inline variable template.
° Still Stands The Question
Is there only one good reason for having defined these 'helper' variable templates for all the types deriving from std::integral_constant ???
° In Other Words
After the comment of #NicolBolas about:
"Why instantiating some object only to convert it into a compile-time value ?"
I realized that the main point behind the question was maybe not enough clear. So I will put it like that:
If you only had at disposal the features provided with C++11, How would you implement 'something' to provide this compile-time value ?
The main benefits are compilation speed, consistency, and convenience, primarily. I'm going to take a look at a few things here. I'll try to address both what the features are used for, and how one would implement them with only C++11 features. If you only care about the implementation ideas, skip to the bottom.
integral_constant itself:
First, we have the central object here, std::integral_constant. It defines a compile-time static constant, accessed as std::integral_constant<T, V>::value, and looks something like thistaken from cppreference.
template<class T, T v>
struct integral_constant {
static constexpr T value = v;
using value_type = T;
using type = integral_constant; // using injected-class-name
constexpr operator value_type() const noexcept { return value; }
constexpr value_type operator()() const noexcept { return value; } // since c++14
};
Now, the first thing to note is that integral_constant stores the constant's value within itself, as a compile-time constant. You can access it without instantiating an instance; furthermore, instantiating the integral_constant will typically just result in an object being created and immediately converted to the constant, doing extra work for zero benefit; it's usually better to just use integral_constant::value directly instead.
constexpr bool TraitResult = integral_constant<bool, SomeConstexprTest(param)>::value;
SFINAE, Traits, and bool_constant:
The most common use case for integral_constant, by far, is as a compile-time boolean trait, likely used for SFINAE or introspection. The vast majority of <type_traits> consists of integral_constant<bool>s, with values determined according to the trait's logic, for use as yes-or-no tests.
template<typename T>
typename std::enable_if< std::is_same<SomeType, T>::value>::type
someFunc(T&& t);
template<typename T>
typename std::enable_if< !std::is_same<SomeType, T>::value>::type
someFunc(T&& t);
C++17 supplies bool_constant with this usage in mind, as a cleaner way to create boolean constants. It allows for cleaner code by simplifying the creation of custom traits:
namespace detail {
// These lines are clean.
template<typename...> struct are_unique_helper;
template<typename T> struct are_unique_helper<T> : std::true_type {};
// This... less so.
template<typename T, typename U, typename... Ts>
struct are_unique_helper<T, U, Ts...> : std::integral_constant<
bool,
!std::is_same<T, U> &&
are_unique_helper<T, Ts...>::value
> {};
}
// With integral_constant<bool>.
template<typename T, typename... Ts>
struct are_unique : std::integral_constant<bool, detail::are_unique_helper<T, Ts...>::value && are_unique<Ts...>::value> {};
// With bool_constant.
template<typename T, typename... Ts>
struct are_unique : std::bool_constant<detail::are_unique_helper<T, Ts...>::value && are_unique<Ts...>::value> {};
The name bool_constant conveys the same information as integral_constant<bool> with less wasted space or one less line, depending on coding style, and has the additional advantange of clearer conveyance thanks to emphasising the bool part. It's not strictly necessary, and can be easily supplied manually if your compiler doesn't support it, but it does provide a few benefits.
true_type and false_type:
These two provide specific constants for true and false; this is definitely useful, but many traits determine v with boolean logic. (See, e.g., std::is_same or are_unique above.) They're neither a be-all nor an end-all, though they can serve useful purposes such as base values for traits (as above, or as in std::is_same), or matching traits for overloading or SFINAE.
constexpr std::string_view isIntInner( std::true_type) { return "yes"; }
constexpr std::string_view isIntInner(std::false_type) { return " no"; }
template<typename T>
constexpr std::string_view isInt(T&&) {
return isIntInner(std::is_same<int, T>{});
}
Helpers: Type aliases & variable templates:
To explain the reason for the variable templates, we also want to look at them alongside the helper aliases defined in C++14.
template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type;
template< class T, class U >
inline constexpr bool is_same_v = is_same<T, U>::value;
These mainly exist as a form of convenience, really; they're a bit faster to type, a bit cleaner to read, and require a bit less finger gymnastics. The type aliases were provided first, and the helper variables are mainly there for consistency with them.
How to implement these:
You mentioned that you're aiming to implement everything using C++11 features primarily. This will allow you to provide most of the above:
integral_constant: Requires only C++11 or earlier features. (constexpr and noexcept.)
bool_constant: Introduced in C++17, but requires only C++11 features. (Alias template.)
true_type and false_type: Same as integral_constant.
Introspective logic type traits: Same as integral_constant.
Helper _t aliases: Introduced in C++14, but requires only C++11 features. (Alias template.)
Helper _v variables: Requires C++14 features. (Variable template.)
It wouldn't actually be too hard to provide helper aliases and bool_constant for compilers which don't support it, as long as using templates is supported. Possibly by, e.g., providing them within your library's namespace, in a header which is only loaded on implementations that don't include the aliases, and/or which the library's consumer can enable or disable as necessary during compilation.
While it would take a lot of work to implement variable templates, however, you do have another, more C++11-compliant option: helper functions.
template<typename T, typename U>
inline constexpr bool is_same_v() noexcept {
return std::is_same<T, U>::value;
}
Providing functions of this sort will result in code nearly as clean as the helper variable templates, which can be cleanly switched over to the official variable templates for compilers which provide them. There are a few slight differences between helper functions and helper variables, though I'm not sure if there are any use cases that would actually care about them, and the library would ideally only provide helper functions for compilers which don't themselves provide the _v variables.
Related
Some Background:
I'm working on putting together a templated class which, as part of template specialization, deduces a type to use for one of its members. This data member needs to support being streamed over the wire, and I'm trying to keep the system as flexible and extensible as possible (with the goal that new variants of the type can be created by modifying some high-level elements of the specialization logic without getting into the guts of the implementation code). Some of the existing usages specialize this data member to be an enum, and the streaming code supports converting this value back and forth to a 32-bit integer for transmission over the wire.
Because an enum could be defined (either implicitly or explicitly) to be backed by a different type -- most dangerous in the case being a 64-bit value -- I'd like to be able enforce that if the resolved type is an enum, its underlying type must be a 32-bit integer (more generally, I just need to enforce that it's a maximum of 32 bits, but I'll be worrying about that complexity once the simpler case is working).
My Attempted Solution:
Stitching together some of the tools provided by type_traits, I came up with the following:
#include <cstdint>
#include <type_traits>
using TestedType = /* Logic for deducing a type */;
constexpr bool nonEnumOrIntBacked =
!std::is_enum_v<TestedType>
|| std::is_same_v<std::underlying_type_t<TestedType>, std::int32_t>;
static_assert(nonEnumOrIntBacked,
"TestedType is an enum backed by something other than a 32-bit integer");
However, when I tried to compile this (using Visual Studio 2017 on the latest update), I was met with the error text
'TestedType': only enumeration type is allowed as an argument to compiler intrinsic type trait '__underlying_type'. Seeing this, I tried an alternative formulation using std::disjunction, which I believe should short-circuit evaluation of templates if an earlier condition evaluates to true (I've ommitted the std qualifiers to make this a bit more readable):
disjunction_v<
negation<is_enum<TestedType>>,
is_same<underlying_type_t<TestedType>, int32_t>
>;
I've also tried wrapping the offending usage of underlying_type_t inside an enable_if predicated on the type being an enum, but didn't have success with that either.
My Question:
Do boolean operators in general (and std::disjunction in particular) not short-circuit evaluation of templates? On the cppreference page for std::disjunction, it states the following (emphasis mine):
Disjunction is short-circuiting: if there is a template type argument Bi with bool(Bi::value) != false, then instantiating disjunction::value does not require the instantiation of Bj::value for j > i
Reading this, I would have expected the ill-formed nature of underlying_type_t<TestedType> for some non-enum type to be irrelevant, since downstream types don't need to be considered once something upstream has been evaluated as true.
If my reading of the spec is incorrect on this point, is there another way to accomplish this check at compile-time, or will I need to add a runtime check to enforce this?
Template arguments are "evaluated" eagerly just like regular arguments. The part causing problems is underyling_type_t, but it's present in full in both versions. You need to delay that part until after you know TestedType is an enum type. This is fairly straightforward with constexpr if (live example):
template<typename T>
constexpr bool nonEnumOrIntBackedImpl() {
if constexpr (std::is_enum_v<T>) {
return std::is_same_v<std::underlying_type_t<T>, std::int32_t>;
} else {
return false;
}
}
template<typename T>
constexpr bool nonEnumOrIntBacked = nonEnumOrIntBackedImpl<T>();
Prior to C++17, one common method is tag dispatching (live example):
template<typename T>
constexpr bool nonEnumOrIntBackedImpl(std::true_type) {
return std::is_same<std::underlying_type_t<T>, std::int32_t>{};
}
template<typename T>
constexpr bool nonEnumOrIntBackedImpl(std::false_type) {
return false;
}
template<typename T>
constexpr bool nonEnumOrIntBacked = nonEnumOrIntBackedImpl<T>(std::is_enum<T>{});
chris explained why the construct failed and gave a solution. But in the spirit of exploiting every single feature of the library, here's how to use the short-circuitry
template<typename T, typename I>
struct is_underlying
{
static constexpr auto value =
std::is_same_v<std::underlying_type_t<T>, I>;
};
using TestedType = int;
constexpr bool nonEnumOrIntBacked =
std::disjunction_v<std::negation<std::is_enum<TestedType>>,
is_underlying<TestedType, std::int32_t>>;
The template needs to be well-formed, but not its value.
An alternative:
template <typename T> struct identity { using type = T; };
bool nonEnumOrIntBacked =
std::is_same<
std::conditional_t<
std::is_enum_v<TestedType>,
std::underlying_type<TestedType>,
identity<void>>::type,
int
>::value
;
with conditional<cont, type1, type2>::type::type :) to delay evaluation.
I'm wondering, what is the rationale behind introducing std::bool_constant and its subsequent use for std::true_type and std::false_type (as well as the comparison structs defined in header <ratio>, cf. N4389) in C++17?
Thus far I've only been able to locate the papers containing the wording:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4334.html
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4389.html
While both paper refer to a "rationale" -- https://issues.isocpp.org/show_bug.cgi?id=51 -- the linked-to comment feed mostly states that this is "Based on the discussion on c++std-lib*" (presumably referring to the private reflector?) without going into further details.
Here is the the documentation:
http://en.cppreference.com/w/cpp/types/integral_constant
It's pure syntactic sugar. Often, we use e.g. tag-dispatching like so:
void foo_impl(std::false_type) { /*Implementation for stuff (and char) */}
void foo_impl(std::true_type ) { /*Implementation for integers but not char*/}
template <typename T>
void foo(T) {
foo_impl(t, std::bool_constant<std::is_integral<T>{} && !std::is_same<char, T>{}>());
}
Without bool_constant, we'd have to use a longer type-specifier to designate the desired type: std::integral_constant<bool, ...>. Since the usage of integral_constant for boolean values pops up especially often, a concise and short way of adressing the specializations was asked for, and bool_constant provides that.
In fact, bool_constant is nothing more than an alias template for bool-specializations of integral_constant:
template <bool B>
using bool_constant = integral_constant<bool, B>;
The only reason the declarations for true_type and false_type (and other uses of integral_constant<bool, ..>) were altered is for brevity in the standard, even; There was no technical need, as integral_constant<bool, false> and bool_constant<false> designate the exact same type.
The C++11 standard specifies a type trait std::alignment_of<T> which simply returns the value of alignof(T).
Is there a similar trait for the sizeof operator? Am I just missing it, or was it just missed in the standard, or is there some obscure technical reason why it wasn't specified?
Obviously it is trivial to create such a trait, but I can't imagine it wouldn't have been considered when introducing std::alignment_of.
For context, I have a custom type trait that I use to get the maximum value of a single trait when applied to a list of types.
template <template<class> class Trait, typename F, typename... T>
struct trait_max
: std::integral_constant<decltype(Trait<F>::value),
(Trait<F>::value > trait_max<Trait, T...>::value) ? Trait<F>::value : trait_max<Trait, T...>::value>
{ };
template <template<class> class Trait, typename F>
struct trait_max<Trait, F>
: std::integral_constant<decltype(Trait<F>::value), Trait<F>::value>
{ };
This trait is really handy for when you need know the maximum of a set of types like so:
auto max_align = traits_max<std::alignment_of, int, float, std::string>::value;
auto max_size = traits_max<std::size_of, int, float, std::string>::value; // doesn't exist
std::alignment_of isn't new in C++11. It was added (along with the rest of <type_traits>) as part of TR1 in 2007. TR1's <type_traits> was copied wholesale from Boost TypeTraits, which provided alignment_of only because there was no standard way to get at that value in 2005.
Of course in 2005 there was a way to get the size of a type T; it has been spelled sizeof(T) since time immemorial. That's why size_of<T> wasn't in Boost TypeTraits, and that's why it wasn't copied into TR1 in 2007, and that's why it wasn't grandfathered into C++11.
As of 2011, there is also a standard way to get the alignment of a type T; it's spelled alignof(T). The pre-2011 construct std::alignment_of<T>::value is needlessly verbose, and you almost certainly shouldn't be using it anymore unless you're concerned about portability to pre-2011 implementations.
I believe the most idiomatic way of writing your sample code is
size_t max_align = std::max({alignof(int), alignof(float), alignof(std::string)});
size_t max_size = std::max({sizeof(int), sizeof(float), sizeof(std::string)});
Once C++14 rolls around, std::max will become constexpr, so this will be computed at compile-time and be usable in template metaprogramming. But the suckiness of C++11's std::max is a totally separate issue, unrelated to your question. :)
EDIT: Here's a constexpr_max that works in today's C++11. Unfortunately C++11's std::initializer_list can't be used in a constexpr context; C++14 is fixing that too.
template<typename T> constexpr T constexpr_max(T t, T u) {
return t > u ? t : u;
}
template<typename T, typename... TT> constexpr T constexpr_max(T t, TT... ts) {
return constexpr_max(t, constexpr_max(ts...));
}
Say I want do something for integral types but not chars and I have
is_integral<T>::type and is_char<T>::type
Is it possible to write this:
integral_constant<bool,is::integral<T>::value && !is_char<T>::value>
more readable
Those kinds of metacomputations were done even before C++11 and Boost.MPL is the heavy artillery of TMP in C++03. With it, your requirements can be expressed like so:
// in C++03:
// typedef /* compute */ result;
using result = and_<is_integral<T>, not_<is_char<T>>>;
(Where and_ and not_ are from the boost::mpl namespaces.)
Notice the limited verbosity because you don't have to put with the ::value boilerplate. Similarly, result is lazy, where you can force computing the result with either result::value (which would be true or false) or result::type (which would be, well, a type -- the documentation has all the details). Boost.MPL makes it easy not to do that though, so for instance not_<result> is enough to invert the logic, even though not_<result::type> would also work. A good thing considering that an additoinal typename is needed if result is dependent.
I do consider Boost.MPL of enormous help in C++03 partly because it emulates variadic templates. For instance, and_ is not restricted to two arguments. I've shied away from it in C++11 however because in most situations where I used it I now use pack expansion. Things like and_ are still useful though because it is not possible to expand a pack in arbitrary expressions, e.g. in one that involves the && logical operator. This can only be done with a logical metafunction:
// Enforce precondition: every type T must be integral
static_assert( and_<std::is_integral<T>...>::value, "Violation" );
I consider this article a good read that gives good hints to reduce the verbosity of metacomputations. It focuses on SFINAE as used for generic programming but it is applicable to TMP as well (and SFINAE can be used in TMP as well). The final example is
template <typename T,
EnableIf<is_scalable<T>, is_something_else<T>>...>
T twice(T t) { return 2*t; }
which could look like this in C++03, using facilities similar to those provided in Boost:
template<typename T>
typename enable_if<
and_<is_scalable<T>, is_something_else<T>>
, T
>::type twice(T t) { return 2*t; }
A naive C++11 version arguably looks the worst:
template<typename T>
typename std::enable_if<
is_scalable<T>::value && is_something_else<T>::value
, T
>::type twice(T t) { return 2*t; }
I've seen some that advocate moving away from the style of Boost.MPL, which favours types and type-'returning' metafunctions towards using values and constexpr functions. This could look like:
// EnableIf alias now accepts non-type template parameters
template<typename T
, EnableIf<is_scalable<T>() && is_something_else<T>()>...>
T twice(T t) { return 2*t; }
You'd still need a constexpr function to compute e.g. the logical disjunction if T... is a pack though: EnableIf<any(is_foo<T>()...)>.
Why do you need an integral constant? If you just need a compile-time constant bool then you don't have to wrap the expression.
is_integral<T>::value && !is_char<T>::value
If you need this expression in several places you can just write you own special type trait.
template<typename T>
struct is_integral_and_not_char {
static const bool value = is_integral<T>::value && !is_char<T>::value;
};
is_integral_and_not_char<T>::value
Or if you do want to conform to the UnaryTypeTrait concept then
template<typename T>
struct is_integral_and_not_char
: std::integral_constant<bool, std::is_integral<T>::value && !std::is_char<T>::value>
{}
Is there any reason why the standard specifies them as template structs instead of simple boolean constexpr?
In an additional question that will probably be answered in a good answer to the main question, how would one do enable_if stuff with the non-struct versions?
One reason is that constexpr functions can't provide a nested type member, which is useful in some meta-programming situations.
To make it clear, I'm not talking only of transformation traits (like make_unsigned) that produce types and obviously can't be made constexpr functions. All type traits provide such a nested type member, even unary type traits and binary type traits. For example is_void<int>::type is false_type.
Of course, this could be worked around with std::integral_constant<bool, the_constexpr_function_version_of_some_trait<T>()>, but it wouldn't be as practical.
In any case, if you really want function-like syntax, that is already possible. You can just use the traits constructor and take advantage of the constexpr implicit conversion in integral_constant:
static_assert(std::is_void<void>(), "void is void; who would have thunk?");
For transformation traits you can use a template alias to obtain something close to that syntax:
template <bool Condition, typename T = void>
using enable_if = typename std::enable_if<Condition, T>::type;
// usage:
// template <typename T> enable_if<is_void<T>(), int> f();
//
// make_unsigned<T> x;
Note: this ends up looking more like a rant than a proper answer... I did got some itch reading the previous answers though, so please excuse me ;)
First, class traits are historically done with template structures because they predate constexpr and decltype. Without those two, it was a bit more work to use functions, though the various library implementations of is_base_of had to use functions internally to get the inheritance right.
What are the advantages of using functions ?
inheritance just works.
syntax can be more natural (typename ::type looks stupid TM)
a good number of traits are now obsolete
Actually, inheritance is probably the main point against class traits. It's annoying as hell that you need to specialize all your derived classes to do like momma. Very annoying. With functions you just inherit the traits, and can specialize if you want to.
What are the disadvantages ?
packaging! A struct trait may embed several types/constants at once.
Of course, one could argue that this is actually annoying: specializing iterator_traits, you just so often gratuitously inherit from std::iterator_traits just to get the default. Different functions would provide this just naturally.
Could it work ?
Well, in a word where everything would be constexpr based, except from enable_if (but then, it's not a trait), you would be going:
template <typename T>
typename enable_if<std::is_integral(T()) and
std::is_signed(T())>::type
Note: I did not use std::declval here because it requires an unevaluated context (ie, sizeof or decltype mostly). So one additional requirement (not immediately visible) is that T is default constructible.
If you really want, there is a hack:
#define VALUE_OF(Type_) decltype(std::declval<T>())
template <typename T>
typename enable_if<std::is_integral(VALUE_OF(T)) and
std::is_signed(VALUE_OF(T))>::type
And what if I need a type, not a constant ?
decltype(common_type(std::declval<T>(), std::declval<U>()))
I don't see a problem either (and yes, here I use declval). But... passing types has nothing to do with constexpr; constexpr functions are useful when they return values that you are interested in. Functions that return complex types can be used, of course, but they are not constexpr and you don't use the value of the type.
And what if I need to chain trais and types ?
Ironically, this is where functions shine :)
// class version
template <typename Container>
struct iterator { typedef typename Container::iterator type; };
template <typename Container>
struct iterator<Container const> {
typedef typename Container::const_iterator type;
};
template <typename Container>
struct pointer_type {
typedef typename iterator<Container>::type::pointer_type type;
};
template <typename Container>
typename pointer_type<Container>::type front(Container& c);
// Here, have a cookie and a glass of milk for reading so far, good boy!
// Don't worry, the worse is behind you.
// function version
template <typename Container>
auto front(Container& c) -> decltype(*begin(c));
What! Cheater! There is no trait defined!
Hum... actually, that's the point. With decltype, a good number of traits have just become redundant.
DRY!
Inheritance just works!
Take a basic class hierarchy:
struct Base {};
struct Derived: Base {};
struct Rederived: Derived {};
And define a trait:
// class version
template <typename T>
struct some_trait: std::false_type {};
template <>
struct some_trait<Base>: std::true_type {};
template <>
struct some_trait<Derived>: some_trait<Base> {}; // to inherit behavior
template <>
struct some_trait<Rederived>: some_trait<Derived> {};
Note: it is intended that the trait for Derived does not state directly true or false but instead take the behavior from its ancestor. This way if the ancestor changes stance, the whole hierarchy follows automatically. Most of the times since the base functionality is provided by the ancestor, it makes sense to follow its trait. Even more so for type traits.
// function version
constexpr bool some_trait(...) { return false; }
constexpr bool some_trait(Base const&) { return true; }
Note: The use of ellipsis is intentional, this is the catch-all overload. A template function would be a better match than the other overloads (no conversion required), whereas the ellipsis is always the worst match guaranteeing it picks up only those for which no other overload is suitable.
I suppose it's unnecessary to precise how more concise the latter approach is ? Not only do you get rid of the template <> clutter, you also get inheritance for free.
Can enable_if be implemented so ?
I don't think so, unfortunately, but as I already said: this is not a trait. And the std version works nicely with constexpr because it uses a bool argument, not a type :)
So Why ?
Well, the only technical reason is that a good portion of the code already relies on a number of traits that was historically provided as types (std::numeric_limit) so consistency would dictate it.
Furthermore it makes migration from boost::is_* just so easier!
I do, personally, think it is unfortunate. But I am probably much more eager to review the existing code I wrote than the average corporation.
One reason is that the type_traits proposal is older than the constexpr proposal.
Another one is that you are allowed to add specializations for your own types, if needed.
Probably because boost already had a version of type_traits that was implemented with templates.
And we all know how much people on the standards committee copy boost.
I would say the mainreason is that type_traits was already part of tr1 and was therefore basically guaranteed to end up in the standard in more or less the same form, so it predates constexpr. Other possible reasons are:
Having the traits as types allows for overloading functions on the type of the trait
Many traits (like remove_pointer) define a type instead of a value, so they have to be expressed in this way. Having different interfaces for traits defining values and traits defining types seems unnessecary
templated structs can be partial specialized, while functions can't, so that might make the implementation of some traits easier
For your second question: As enable_if defines a type (or not, if it is passed false) a nested typedef inside a struct is really the way to go