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

Additional Type Traits for C++0x


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



LWG issue 1174, submitted by Jason Merrill:

I've been implementing compiler support for is_standard_layout, and noticed a few nits about [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. ]


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 [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:

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.


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.


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.

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;

//, 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;

//, 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;

//, 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> 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;

//, 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;

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

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

//, array modifications:
template <class T> struct remove_extent;
template <class T> struct remove_all_extents;
//, 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 enum_base;

} // namespace std

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

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.

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

Template Condition Comments
template <class From, class To>
struct is_explicitly_convertible;
See below. From and To shall be complete types, arrays of unknown bound, or (possibly cv-qualified) void types.

At the end of 20.6.5 Relationships between types [meta.rel], change as indicated. (Assumes issue 975 has been applied to the WP. Editor please note change to bulleted list):

Given the following function prototype:

template <class T>
typename add_rvalue_reference<T>::type create();
To test() {
  return create<From>();

[ Note: This requirement gives well defined results for reference types, void types, array types, and function
types.—end note ]


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

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