Document number: N2984=09-0174
Date: 2009-10-23
Project: Programming Language C++, Library Working Group
Reply-to: Beman Dawes <bdawes at acm dot org>
Daniel Krügler <daniel.kruegler at googlemail dot com>
Alisdair Meredith <public at alisdairm dot net>

Additional Type Traits for C++0x (Revision 1)

Introduction

The C++ committee's Library Working Group (LWG) asked in Frankfurt for a proposal unifying LWG requests for additional type traits in light of the  removal of the concepts language feature from C++0x.

Revision history

N2984 - Revision 1

N2947 - Initial version.

Rationale

is_trivially_copyable

LWG issue 1174, submitted by Jason Merrill:

I've been implementing compiler support for is_standard_layout, and noticed a few nits about 20.6.4.3 [meta.unary.prop]:

  1. There's no trait for "trivially copyable type", which is now the property that lets you do bitwise copying of a type, and therefore seems useful to be able to query. has_trivial_assign && has_trivial_copy_constructor && has_trivial_destructor is similar, but not identical, specifically with respect to const types.
  2. has_trivial_copy_constructor and has_trivial_assign lack the "or an array of such a class type" language that most other traits in that section, including has_nothrow_copy_constructor and has_nothrow_assign, have; this seems like an oversight.

[ See the thread starting with c++std-lib-24420 for further discussion. ]

is_trivially_copyable is believed to require compiler support.

is_literal_type

LWG issue 719, submitted by Daniel Krügler:

Since the inclusion of constexpr in the standard draft N2369 we have a new type category "literal", which is defined in 3.9 [basic.types]/p.11:

-11- A type is a literal type if it is:

I strongly suggest that the standard provides a type traits for literal types in 20.6.4.3 [meta.unary.prop] for several reasons:

  1. To keep the type traits in sync with the types defined in the core language.
  2. I see many reasons for programmers to use this trait in template code to provide optimized template definitions for these types, see below.
  3. A user-provided definition of this trait is practically impossible to write portably.

The special problem of reason (c) is that I don't see currently a way to portably test the condition for literal class types:

is_literal_type is believed to require compiler support.

The proposed name is is_literal_type, rather than is_literal, because literal and literal type have different core language meanings. It was judged better to be clear even at the cost of being inconsistent with the other names.

is_nothrow_constructible

This is a critical trait that came out of exception-safety considerations discussed in N2953, Defining Move Special Member Functions, given the possible presence of throwing and non-throwing copy/move operations.

From N2953:

"However, throwing moves are problematic within the library, and some library specifications prohibit throwing moves. To enable conditional definition of move operations within the library, we add an is_nothrow_constructible variadic type trait."

is_nothrow_constructible is believed to require compiler support.

is_constructible

is_constructible is the foundation upon which is_nothrow_constructible and is_explictly_convertible are built.

is_constructible is believed to require compiler support.

Omitting is_constructible in the presence of is_nothrow_constructible would be inconsistent with other traits that have an is_nothrow_* counterpart.

The cost of specifying this additional trait is outweighed by the consistency concern, and to satisfy user-expectations. Additionally, the trickiest part of the specification of is_nothrow_constructible is the is_constructible subpart. So this work has to be done anyhow.

is_explicitly_convertible

LWG issue 750, submitted by Alisdair Meredith:

The current definition for is_convertible requires that the type be implicitly convertible, so explicit constructors are ignored.

With the pending arrival of explicit conversion functions though, I'm wondering if we want an additional trait, is_explictly_convertible?

Several LWG members have commented that they believe such a trait would be useful.

is_explicitly_convertible is believed to require compiler support unless is_constructible is available.

underlying_type

LWG issue 1055, addressing CD-1comment UK 98:

It would be useful to be able to determine the underlying type of an arbitrary enumeration type. This would allow safe casting to an integral type (especially needed for scoped enums, which do not promote), and would allow use of numeric_limits. In general it makes generic programming with enumerations easier.

underlying_type is believed to require compiler support.

Proposed wording

To 20.6.2 Header <type_traits> synopsis [meta.type.synop], add as indicated:

namespace std {

// 20.6.3, helper class:
template <class T, T v> struct integral_constant;
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;

// 20.6.4.1, primary type categories:
template <class T> struct is_void;
template <class T> struct is_integral;
template <class T> struct is_floating_point;
template <class T> struct is_array;
template <class T> struct is_pointer;
template <class T> struct is_lvalue_reference;
template <class T> struct is_rvalue_reference;
template <class T> struct is_member_object_pointer;
template <class T> struct is_member_function_pointer;
template <class T> struct is_enum;
template <class T> struct is_union;
template <class T> struct is_class;
template <class T> struct is_function;

// 20.6.4.2, composite type categories:
template <class T> struct is_reference;
template <class T> struct is_arithmetic;
template <class T> struct is_fundamental;
template <class T> struct is_object;
template <class T> struct is_scalar;
template <class T> struct is_compound;
template <class T> struct is_member_pointer;

// 20.6.4.3, type properties:
template <class T> struct is_const;
template <class T> struct is_volatile;
template <class T> struct is_trivial;
template <class T> struct is_trivially_copyable;
template <class T> struct is_standard_layout;
template <class T> struct is_pod;
template <class T> struct is_literal_type;
template <class T> struct is_empty;
template <class T> struct is_polymorphic;
template <class T> struct is_abstract;
template <class T, class... Args> struct is_constructible;
template <class T, class... Args> struct is_nothrow_constructible;
template <class T> struct has_trivial_default_constructor;
template <class T> struct has_trivial_copy_constructor;
template <class T> struct has_trivial_assign;
template <class T> struct has_trivial_destructor;
template <class T> struct has_nothrow_default_constructor;
template <class T> struct has_nothrow_copy_constructor;
template <class T> struct has_nothrow_assign;
template <class T> struct has_virtual_destructor;
template <class T> struct is_signed;
template <class T> struct is_unsigned;
template <class T> struct alignment_of;
template <class T> struct rank;
template <class T, unsigned I = 0> struct extent;

// 20.6.5, type relations:
template <class T, class U> struct is_same;
template <class Base, class Derived> struct is_base_of;
template <class From, class To> struct is_convertible;
template <class From, class To> struct is_explicitly_convertible;

// 20.6.6.1, const-volatile modifications:
template <class T> struct remove_const;
template <class T> struct remove_volatile;
template <class T> struct remove_cv;
template <class T> struct add_const;
template <class T> struct add_volatile;
template <class T> struct add_cv;

// 20.6.6.2, reference modifications:
template <class T> struct remove_reference;
template <class T> struct add_lvalue_reference;
template <class T> struct add_rvalue_reference;

// 20.6.6.3, sign modifications:
template <class T> struct make_signed;
template <class T> struct make_unsigned;

// 20.6.6.4, array modifications:
template <class T> struct remove_extent;
template <class T> struct remove_all_extents;
// 20.6.6.5, pointer modifications:
template <class T> struct remove_pointer;
template <class T> struct add_pointer;

// 20.6.7, other transformations:
template <std::size_t Len, std::size_t Align> struct aligned_storage;
template <std::size_t Len, class... Types> struct aligned_union;
template <class T> struct decay;
template <bool, class T = void> struct enable_if;
template <bool, class T, class F> struct conditional;
template <class... T> struct common_type;
template <class T> struct underlying_type;

} // namespace std

To 20.6.4.3 Type properties [meta.unary.prop], table Type property predicates, add rows:

Template Condition Preconditions
template <class T>
struct is_trivially_copyable;
T is a trivially copyable type ([basic.types]) T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
template <class T>
struct is_literal_type;
T is a literal type ([basic.types]) T shall be a complete type, an array of unknown bound, or (possibly cv-qualified) void.
template <class T, class... Args> struct is_constructible; See below T and all types in the parameter pack Args shall be complete types, arrays of unknown bound, or (possibly cv-qualified) void types.
template <class T, class... Args> struct is_nothrow_constructible; is_constructible<T, Args...>::value is true and the expression CE, as defined below, is known not to throw any exceptions. T and all types in the parameter pack Args shall be complete types, arrays of unknown bound, or (possibly cv-qualified) void types.

To 20.6.4.3 Type properties [meta.unary.prop], before table Type property queries, add:

Given the following function prototype:

template <class T>
typename add_rvalue_reference<T>::type create();

the predicate condition for a template specialization is_constructible<T, Args...> shall be satisfied, if and only if the following expression CE would be well-formed:

To 20.6.5 Relationships between types [meta.rel], table Type relationship predicates, add row:

Template Condition Comments
template <class From, class To>
struct is_explicitly_convertible;
is_constructible<To, From>::value is_explicitly_convertible is a synonym for a two-argument is_constructible. An implementation may define it as a template alias.

To 20.6.7 Other transformations [meta.trans.other], table Other transformations, add row:

Template Condition Comments
template <class T>
struct underlying_type;
T shall be an enumeration type ([dcl.enum]) The member typedef type shall name the underlying type of the enum T.

Acknowledgements

Howard Hinnant, Lawrence Crowl, and Pablo Halpern contributed ideas and discussions leading to this proposal.