| Document number: | N3804 | 
| Date: | 2013-10-09 | 
| Project: | Programming Language C++ | 
| Reply-to: | Beman Dawes <bdawes at acm dot org> Kevlin Henney <kevlin at curbralan dot com> Daniel Krügler <daniel dot kruegler at gmail dot com> | 
Introduction
Revision History
Motivation and Design
Design paths not taken
Examples
FAQ
Acknowledgements
Proposed Wording
    ValueType 
Requirements
    Header <experimental/any> synopsis
    Class bad_any_cast
    Class any
    Non-member functions
 
This paper proposes a type-safe container for single values of value types. The C++ standards committee is planning to include the proposal in a library Technical Specification (TS).
The proposal is based on the Boost Any Library (see www.boost.org/libs/any). The Boost version of library has been in wide use for over a decade, and the library has been implemented at least twice in addition to the Boost implementation. The proposal is a pure addition to the standard library, requires no modifications to any C++14 standard library components, requires no compiler support, and will have no effect on existing namespace-disciplined code.
N3804 - Revision 3
any introduction to clarify that empty is a 
valid state and to clarify the relationship with any_cast.bad_alloc from Throws: elements to conform with 
standard library conventions.any_cast, replace Returns: 
wording with explicit formulation that distinguishes between const and non-const 
cases, in response to Bristol LEWG concerns. The more explicit formulation also 
leaves less room for misinterpretation by forwarding to the pointer versions of
any_cast.any_cast, remove "[Note: For consistency with the C++ keyword casts, a copy 
is returned.--end note]". The note was confusing people.any_cast, 
illustrating points that have caused questions:
  any_cast to valueany_cast to non-const reference used to modify stored value 
    in the any object.any to store a const char*, and then 
    access it by value and by reference.any to store a std::string, as an 
    example of a movable type, and then move from and to the any 
    object.const any object holding a 
    std::string.const any object.any_cast, revise the 
    signatures to make explicit that the return type is a pointer and that 
    return type constness is determined by argument constness. any_cast, add an explicit 
    requirement that the const argument form return a const qualified pointer, 
    as requested by the LEWG in Bristol.any_cast, change "a null 
    pointer" to nullptr, and make nullptr comparison 
    explicit in the example.any_cast pointer overload example, remove * 
    from the cast type. This was a nasty bug that compiled OK but caused the 
    example function to return the wrong result.noexcept to bad_any_cast::what. (Antony Polukhin)clear() function. (Antony Polukhin) any_cast(any&&) overload, so that rvalue 
    arguments work properly, as requested by the LEWG in Bristol.std::. (Daniel Krügler).any construction and assignment of 
    ValueType from  pass-by-value to pass-by-rvalue-reference. 
    Suggested by Sean Parent as more in keeping with the standard library and by Antony Polukhin's 
    Boost.Any analysis. Daniel Krügler pointed out that a single 
    perfect-forwarding function copes with both const and non-const arguments, 
    and both template pass-by-rvalue-reference constructor and operator= 
    follow his advice.template<typename 
    ValueType> any(ValueType&& value) constructor, constructor 
    with allocator, and operator= because otherwise these functions 
    would catch too much (including non-const values of type any). 
    (Daniel Krügler)noexcept to the first of the allocator constructors. 
    (Daniel Krügler)clear(), and 
    specify clear() effects such that any contained value is 
    destroyed. The wording is such that it is still correct in the presence of 
    small-value optimization. (Daniel Krügler)empty() to avoid a near 
    recursive definition. (Daniel Krügler)type() Returns non-empty case as it 
    was somewhat blurry in that it could be read to mean typeid(this.value) 
    where value is the contained object and could mean that 
    typeid is used as in a polymorphic operation when the value type is a 
    polymorphic type.  (Daniel Krügler)ValueType requirements as 
    tutorial in nature and thus beyond the scope of the standard library or a 
    library TS.ValueType 
    and assignment from ValueType to be more precise and to 
    eliminate errors that had crept in as C++11 features were applied. (Daniel 
    Krügler private email 2013/05/09)ValueType requirements section, and add a 
    Requires element to the signatures that actually require 
    CopyConstructible, following current practice of the 
    standard library for containers.N3508 - Revision 2
swap(swap(" and "tr2" 
    typos. (Daniel Krügler)any::swap to return void, to conform to 
    standard library practice for member swap function return 
    values. (Daniel Krügler)noexcept from any::~any();, to conform 
    to standard library practice. (Daniel Krügler)any default constructor to 
    noexcept. (Daniel Krügler)any& operator=(any rhs) to any& operator=(const any& rhs), 
    and change the effects accordingly. This avoids an ambiguity. (Daniel Krügler, 
    Sean Parent)rhs.empty() postcondition to any& 
    operator=(any&& rhs) noexcept. (Daniel Krügler)any_cast 
    with explicit specification. (Chris 
    Jefferson)ValueType to ValueTypePtr. (Sylvester 
    Hesp)any_cast examples.N3390 - Revision 1
noexcept applied where appropriate.any copy assignment interface updated to match Boost.swap function.any_cast overload.any move constructor (Sean Parent).any move assignment (Sean Parent).any assignment from ValueType to pass by 
    value instead of const reference (Sean Parent).any_cast with pointer argument to require 
    that the template parameter itself be a pointer, to match dynamic_cast. 
    (Thanks to Sean for catching this.) The Boost interface added * 
    to the return type solely to cope with historical compiler issues, and this 
    workaround had crept into the proposal. N1939 - Initial paper
There are times when a generic (in the sense of general as opposed to template-based programming) type is needed: variables that are truly variable, accommodating values of many other more specific types rather than C++'s normal strict and static types. We can distinguish three basic kinds of generic type:
int and 
  string, and freely convert between them, for instance interpreting
  5 as "5" 
  or vice-versa. Such types are common in scripting and other interpreted 
  languages. boost::lexical_cast supports 
  such conversion functionality.5 is 
  held strictly as an int and is not 
  implicitly convertible either to "5" or to
  5.0. Their indifference to interpretation 
  but awareness of type effectively makes them safe, generic containers of 
  single values, with no scope for surprises from ambiguous conversions.void *, 
  which offers plenty of scope for surprising, undefined behavior.The proposed any class (based on the class of the same name 
described in
"Valued Conversions" by Kevlin Henney, C++ Report 
12(7), July/August 2000) is a variant value type based on the second category. 
It supports copying of any value type and safe checked extraction of that value 
strictly against its type.
In several aspects, the design of std::any can be compared to
std::function. This proposal differs from the specification of
std::function type-erasure policy by emphasizing the worth of having
guaranteed nothrow
move-operations. While std::function imposes little restrictions upon
the wrapped function object types where the small-object optimization
can be applied, in this proposal std::any restricts these cases to
those where the copy/move operations of the contained object cannot
throw exceptions.
A similar design, offering more appropriate operators, could be used for a generalized function adaptor, a generalized iterator adaptor, and other object types that need uniform runtime treatment but support only compile-time template parameter conformance. Such components are not proposed here.
The following code demonstrates the syntax for using implicit conversions to and copying of any objects:
#include <list> #include <experimental/any> usingstd::experimental::any_cast; using std::experimental::any; typedef std::list<any> many; void append_int(many& values, int value) {anyto_append = value; values.push_back(to_append); } void append_string(many& values, const std::string& value) { values.push_back(value); } void append_char_ptr(many& values, const char* value) { values.push_back(value); } void append_any(many& values, constany& value) { values.push_back(value); } void append_nothing(many& values) { values.push_back(any()); }
The following predicates follow from the previous definitions and demonstrate the use of queries on any objects:
bool is_empty(constany& operand) { return operand.empty(); } bool is_int(constany& operand) { return operand.type() == typeid(int); } bool is_char_ptr(constany& operand) { try {any_cast<const char *>(operand); return true; } catch(conststd::tbd::bad_any_cast&) { return false; } } bool is_string(constany& operand) { returnany_cast<std::string*>(&operand); } void count_all(many& values, std::ostream& out) { out << "#empty == " << std::count_if(values.begin(), values.end(), is_empty) << std::endl; out << "#int == " << std::count_if(values.begin(), values.end(), is_int) << std::endl; out << "#const char * == " << std::count_if(values.begin(), values.end(), is_char_ptr) << std::endl; out << "#string == " << std::count_if(values.begin(), values.end(), is_string) << std::endl; }
The following type, patterned after the OMG's Property Service, defines name-value pairs for arbitrary value types:
  struct property
{
    property();
    property(const std::string&, const any&);
    std::string name;
    any value;
};
typedef std::list<property> properties;
The following base class demonstrates one approach to runtime polymorphism based callbacks that also require arbitrary argument types. The absence of virtual member templates requires that different solutions have different trade-offs in terms of efficiency, safety, and generality. Using a checked variant type offers one approach:
  class consumer
{
public:
    virtual void notify(const any&) = 0;
    ...
};
What is the relationship between Boost.any and Boost.variant?
Boost::any is like a "typesafe void*", while Boost::variant is a "typesafe union".
Sean Parent and Daniel Krügler provided numerous comments, corrections, and suggestions, and were particularly helpful applying C++11 features to the library. Sean also provided a copy of his Adobe C++ implementation. Daniel's expertise with library standardese markedly improved the proposed wording. Antony Polukhin, the maintainer of the Boost implementation, provided a helpful analysis of differences between the Boost implementation and the proposal.
Commentary that is not part of the proposed wording is shaded in gray.
Add the following section to the library TS working paper at a location to be determined by the project editor:
This clause describes components that C++ programs may use to perform operations on objects of a discriminated type.
[Note: The discriminated type may contain values of different types but does not attempt conversion between them, i.e.
5is held strictly as anintand is not implicitly convertible either to"5"or to5.0. This indifference to interpretation but awareness of type effectively allows safe, generic containers of single values, with no scope for surprises from ambiguous conversions. -- end note.]
  namespace std { namespace experimental { inline namespace any_v1 {
  class bad_any_cast : public bad_cast
  {
  public:
    virtual const char* what() const noexcept;
  };
  class any
  {
  public:
    // construct/destruct
    any() noexcept;
    any(const any& other);
    any(any&& x) noexcept;
    template <typename ValueType>
      any(ValueType&& value);
    template <class Allocator>
      any(allocator_arg_t, const Allocator& a) noexcept;
    template <class Allocator, typename ValueType>
      any(allocator_arg_t, const Allocator& a, ValueType&& value);
    template <class Allocator>
      any(allocator_arg_t, const Allocator& a, const any& other);
    template <class Allocator>
      any(allocator_arg_t, const Allocator& a, any&& other) noexcept;
   ~any();
  
    // assignments
    any& operator=(const any& rhs);
    any& operator=(any&& rhs) noexcept;
    template <typename ValueType>
      any& operator=(ValueType&& rhs);
    // modifiers
    void clear() noexcept;
    void swap(any& rhs) noexcept;
    // observers
    bool empty() const noexcept;
    const type_info& type() const noexcept;
  };
  void swap(any& x, any& y) noexcept;
  template<typename ValueType>
    ValueType any_cast(const any& operand);
  template<typename ValueType>
    ValueType any_cast(any& operand);
  template<typename ValueType>
    ValueType any_cast(any&& operand);
  template<typename ValueType>
    const ValueType* any_cast(const any* operand) noexcept;
  template<typename ValueType>
    ValueType* any_cast(any* operand) noexcept;
}}}
bad_any_castObjects of type bad_any_cast are thrown by a failed 
any_cast.
anyAn object of class any stores an instance of any type that 
satisfies the constructor requirements or is empty, and this is referred to as 
the state of the class  any object. The stored 
instance is called the contained object. Two states are equivalent if they are either both empty or if
both are not empty and if the contained objects are equivalent.
The non-member any_cast 
functions provide type-safe access to the contained object.
Implementations should avoid the use of dynamically allocated memory for a small contained object. [Example: where the object constructed is holding only an int. -- end example] Such small-object optimization shall only be applied to nothrow copyable types.
| The use of "should" in the above paragraph provides ISO normative encouragement. This is a deliberate design decision. | 
any construct/destructany() noexcept;
Postconditions:
this->empty()
any(const any& other);
Effects: Constructs an object of type
anywith an equivalent state asother.Throws: Any exceptions arising from the copy constructor of the contained object.
any(any&& other) noexcept;
Effects: Constructs an object of type
anywith a state equivalent to the original state ofother.Postconditions:
otheris left in a valid but otherwise unspecified state.
template<typename ValueType> any(ValueType&& value);
Let
Tbe equal todecay<.ValueType>::type Requires:
Tshall satisfy the CopyConstructible requirements. Ifis_copy_constructible<T>::valueis false, the program is ill-formed.Effects: Constructs an object of type
anythat contains an object of typeTdirect-initialized withstd::forward<ValueType>(value).Remarks: This constructor shall not participate in overload resolution if
decay<ValueType>::typeis the same type asstd::any.Throws: Any exception thrown by the selected constructor of
T.
template <class Allocator> any(allocator_arg_t, const Allocator& a) noexcept; template <class Allocator, typename ValueType> any(allocator_arg_t, const Allocator& a, ValueType&& value); template <class Allocator> any(allocator_arg_t, const Allocator& a, const any& other); template <class Allocator> any(allocator_arg_t, const Allocator& a, any&& other) noexcept;
Requires:
Allocatorshall meet the requirements for an Allocator ([allocator.requirements]).Effects: Equivalent to the preceding constructors except that the contained object is constructed with uses-allocator construction ([allocator.uses.construction]) if memory allocation is performed.
~any();
Effects:
clear().
any assignmentsany& operator=(const any& rhs);
Effects:
any(rhs).swap(*this), however, no effects if an exception is thrown.Returns:
*thisThrows: Any exceptions arising from the copy constructor of the contained object.
any& operator=(any&& rhs) noexcept;
Effects:
any(std::move(rhs)).swap(*this).Returns:
*thisPostconditions: The state of
*thisis equivalent to the original state ofrhsandrhsis left in a valid but otherwise unspecified state.
template<typename ValueType> any& operator=(ValueType&& rhs);
Let
Tbe equal todecay<.ValueType>::type Requires:
Tshall satisfy the CopyConstructible requirements. Ifis_copy_constructible<T>::valueis false, the program is ill-formed.Effects: Constructs an object
tmpof typeanythat contains an object of typeTdirect-initialized withstd::forward<ValueType>(rhs), andtmp.swap(*this); however, no effects if an exception is thrown.Returns:
*thisRemarks: This operator shall not participate in overload resolution if
decay<ValueType>::typeis the same type asstd::any.Throws: Any exception thrown by the selected constructor of
T.
any modifiersvoid clear() noexcept;
Effects: If not empty, destroys the contained object.
Postconditions:
empty() == true.
void swap(any& rhs) noexcept;
Effects: Exchange the states of
*thisandrhs.
any observersbool empty() const noexcept;
Returns:
trueif*thishas no contained object, otherwisefalse.
const type_info& type() constnoexcept;
Returns: If
*thishas a contained object of type T,typeid(T); otherwisetypeid(void).[Note: Useful for querying against types known either at compile time or only at runtime. --end note]
void swap(any& x, any& y) noexcept; 
    Effects: x.swap(y).
  | The following 
      specifications for any_casthave been 
      revised to increase clarity. For the existing two signatures these changes 
      were to exposition 
      only. The actual behavior is unchanged from prior revisions.The examples have been compiled and tested with GCC and VC++. | 
template<typename ValueType> ValueType any_cast(const any& operand); template<typename ValueType> ValueType any_cast(any& operand); template<typename ValueType> ValueType any_cast(any&& operand);
Requires:
is_reference<ValueType>::valueis true oris_copy_constructible<ValueType>::valueis true. Otherwise the program is ill-formed.Returns: For the first form,
*any_cast<typename add_const<typename remove_reference<ValueType>::type>::type >(&operand). For the second and third forms,*any_cast<typename remove_reference<ValueType>::type>(&operand).Throws:
bad_any_castifoperand.type() != typeid(remove_reference<ValueType>::type).[Example:
any x(5); // x holds int assert(any_cast<int>(x) == 5); // cast to value any_cast<int&>(x) = 10; // cast to reference assert(any_cast<int>(x) == 10); x = "Meow"; // x holds const char* assert(strcmp(any_cast<const char*>(x), "Meow") == 0); any_cast<const char*&>(x) = "Harry"; assert(strcmp(any_cast<const char*>(x), "Harry") == 0); x = string("Meow"); // x holds string string s, s2("Jane"); s = move(any_cast<string&>(x)); // move from any assert(s == "Meow"); any_cast<string&>(x) = move(s2); // move to any assert(any_cast<const string&>(x) == "Jane"); string cat("Meow"); const any y(cat); // const y holds string assert(any_cast<const string&>(y) == cat); any_cast<string&>(y); // error; cannot // any_cast away const--end example]
template<typename ValueType> const ValueType* any_cast(const any* operand) noexcept; template<typename ValueType> ValueType* any_cast(any* operand) noexcept;
Returns: If
operand != nullptr && operand->type() == typeid(ValueType), a pointer to the object contained byoperand, otherwisenullptr.[Example:
bool is_string(const any& operand) { return any_cast<string>(&operand) != nullptr; }--end example]
© Copyright 2001, 2012, 2013 Kevlin Henney
© Copyright 2006, 2012, 2013 Beman Dawes
© Copyright 2013 Daniel Krügler