| 
       Document number:  | 
      N3508 | 
| Date: | 2013-01-11 | 
| Project: | Programming Language C++ | 
| Reply-to: | Beman Dawes <bdawes at acm dot org> Kevlin Henney <kevlin at curbralan dot com>  | 
    
Introduction
Revision History
Motivation and Design
Design paths not taken
Examples
FAQ
Do list
Acknowledgements
Proposed Wording
    ValueType 
Requirements
    Header <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's Library Working Group reviewed the proposal at the October, 2012, meeting and is tentatively targeting the proposal for the C++ Standard update referred to as C++14. The proposal would also be suitable for 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++11 standard library components, requires no compiler support, and will have no effect on existing namespace-disciplined code.
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)Add rhs.empty() postcondition to any& 
    operator=(any&& rhs) noexcept. (Daniel Krügler)
Replace "successful" and "unsuccessful" in any_cast 
    with explicit specification. (Chris 
    Jefferson)
Change name of template parameter for pointer flavor of  
    from ValueType to ValueTypePtr. (Sylvester 
    Hesp)
Add 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.
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 <any> usingstd::tbd::any_cast; using std::tbd::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".
any_cast 
    template parameter? Do they have any effect?emplace member 
    functions.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 C++ implementation. Sean has done extensive experiments with real C++11 compilers on issues such as pass-by-value versus pass-by-reference. Daniel's expertise with library standardese markedly improved the proposed wording.
Add the following section to the 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.]
ValueType RequirementsA ValueType type shall meet the requirements for CopyConstructible 
[copyconstructible].  
[Note: Values are strongly informational objects for which identity is not significant, i.e. the focus is principally on their state content and any behavior organized around that. Another distinguishing feature of values is their granularity: normally fine-grained objects representing simple concepts in the system such as quantities.
As the emphasis of a value lies in its state not its identity, values can be copied and typically assigned one to another, requiring the explicit or implicit definition of a public copy constructor. Values typically live within other scopes, i.e. within objects or blocks, rather than on the heap. Values are therefore normally passed around and manipulated directly as variables or through references, but not as pointers that emphasize identity and indirection. --end note]
Synopsis additions from the prior version are in green with 
underscores, deletions are in red with strikethroughs.
  namespace std { namespace tbd {
  class bad_any_cast : public std::bad_cast
  {
  public:
    virtual const char* what() const;
  };
  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);
    template <class Allocator, typename ValueType>
      any(allocator_arg_t, const Allocator& a, ValueType value);
   ~any() noexcept;
  
    // assignments
    any& operator=(any rhs);
    any& operator=(const any& rhs);
    any& operator=(any&& rhs) noexcept;
    template <typename ValueType>
      any& operator=(ValueType rhs);
    // modifiers
    any& 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 ValueTypePtr>
    ValueType ValueTypePtr any_cast(const any* operand) noexcept;
  template<typename ValueType ValueTypePtr>
    ValueTypePtr ValueType any_cast(any* operand) noexcept;
}}
bad_any_castObjects of type bad_any_cast are thrown by a failed 
any_cast.
anyObjects of class any hold instances of any type that 
satisfies the ValueType requirements.
any construct/destructany() noexcept;
Postconditions:
this->empty()
any(const any& other);
Effects: Copies content of
otherinto a new instance, so that any content is equivalent in both type and value toother, or empty ifotheris empty.Throws:
bad_allocor any exceptions arising from the copy constructor of the contained type.
any(any&& other) noexcept;
Effects: Moves content of
otherinto a new instance, so that any content is equivalent in both type and value to the original content ofother, or empty ifotheris empty.
template<typename ValueType> any(ValueType value);
Effects: Constructs an object of type
anywith initial content equivalent in both type and value tovalue.Throws:
bad_allocor any exceptions arising from the copy constructor of the contained type.
template <class Allocator> any(allocator_arg_t, const Allocator& a); template <class Allocator, typename ValueType> any(allocator_arg_t, const Allocator& a, ValueType value);
Requires:
Allocatorshall meet the requirements for an Allocator ([allocator.requirements]).Effects: Equivalent to the preceding constructors except that the stored value is constructed with uses-allocator construction ([allocator.uses.construction]).
Throws:
bad_allocor any exceptions arising from the copy constructor of the contained type.[Note: Implementations are encouraged to avoid the use of dynamically allocated memory for small contained types, for example, where the object constructed is holding only an int. —end note ]
~any();
Effects: Releases resources.
any assignmentsany& operator=(const any& rhs);
Effects:
any(rhs).swap(*this), however, no effects if an exception is thrown.Throws:
bad_allocor any exceptions arising from the copy constructor of the contained type.
any& operator=(any&& rhs) noexcept;
Effects: Moves content of
rhsto*this, so that any content is equivalent in both type and value to the original content ofrhs, or empty ifrhsis empty.Postconditions:
rhs.empty().
template<typename ValueType> any& operator=(ValueType rhs);
Effects:
any(rhs).swap(*this), however, no effects if an exception is thrown.Returns:
*thisThrows:
bad_allocor any exceptions arising from the copy constructor of the contained type.
any modifiersvoid swap(any& rhs) noexcept;
Effects: Exchange of the contents of
*thisandrhs.
any observersbool empty() const noexcept;
Returns:
trueif instance is empty, otherwisefalse.
const type_info& type() constnoexcept;
Returns: The
typeidof the contained value if instance is non-empty, 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). 
  
template<typename ValueType> ValueType any_cast(const any& operand); template<typename ValueType> ValueType any_cast(any& operand);
Returns: The value contained by
operand.Throws:
bad_any_castifoperand.type() != typeid(remove_reference<ValueType>::type).[Note: For consistency with the C++ keyword casts, a copy is returned.--end note.]
[Example:
any x; x = 51; any_cast<int&>(x) = 42;--end example]
template<typename ValueTypePtr> ValueTypePtr any_cast(const any* operand) noexcept; template<typename ValueTypePtr> ValueTypePtr any_cast(any* operand) noexcept;
Returns: If
operand != nullptr && operand->type() == typeid(remove_pointer<ValueTypePtr>::type), a pointer to the value contained byoperand, otherwise a null pointer. The returned pointer isconstqualified for the signature with aconstargument.[Example:
bool is_string(const any& operand) { return any_cast<std::string*>(&operand); }--end example]
© Copyright 2001, 2012 Kevlin Henney
© Copyright 2006, 2012 Beman Dawes
Revised 2013-01-11