Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I needed a boost.any lookalike, that could handle a std::unique_ptr. I came up with this. Please provide some c++11 criticism.

#ifndef ANY_HPP
# define ANY_HPP

#include <algorithm>

#include <cassert>

#include <stdexcept>

#include <typeinfo>

#include <type_traits> 

#include <utility>

class any
{
public:
  any() : content(0) { }

  any(any const& other)
    : content(other.content ? other.content->clone() : 0)
  {
  }

  any(any&& other) : content(other.content) { other.content = 0; }

  template<typename ValueType>
  any(ValueType&& value)
    : content(new holder<typename std::remove_reference<ValueType>::type>(
      std::forward<ValueType>(value)))
  {
  }

  ~any() { delete content; }

public: // modifiers

  void swap(any& rhs) { std::swap(content, rhs.content); }

  any& operator=(any const& rhs)
  {
    any(rhs).swap(*this);
    return *this;
  }

  any& operator=(any&& rhs)
  {
    swap(rhs);
    return *this;
  }

  template<typename ValueType>
  any& operator=(ValueType&& rhs)
  {
    any(std::forward<ValueType>(rhs)).swap(*this);
    return *this;
  }

public: // queries

  explicit operator bool() const { return content; }

  std::type_info const& type() const
  {
    return content ? content->type() : typeid(void);
  }

private: // types

  struct placeholder
  {
    placeholder() = default;

    placeholder(placeholder const&) = delete;

    virtual ~placeholder() { }

    virtual placeholder* clone() const = 0;

    virtual std::type_info const& type() const = 0;

    placeholder& operator=(placeholder const&) = delete;
  };

  template<typename ValueType, typename = void>
  struct holder : public placeholder
  {
  public: // constructor
    template <class T>
    holder(T&& value) : held(std::forward<T>(value)) { }

    placeholder* clone() const final
    {
      throw std::invalid_argument(typeid(ValueType).name());
      return 0;
    }

  public: // queries
    std::type_info const& type() const { return typeid(ValueType); }

  public:
    ValueType held;
  };

  template<typename ValueType>
  struct holder<ValueType, typename std::enable_if<
    std::is_copy_constructible<ValueType>::value>::type>
    : public placeholder
  {
  public: // constructor
    template <class T>
    holder(T&& value) : held(std::forward<T>(value)) { }

    placeholder* clone() const final { return new holder<ValueType>(held); }

  public: // queries
    std::type_info const& type() const { return typeid(ValueType); }

  public:
    ValueType held;
  };

private: // representation

  template<typename ValueType>
  friend ValueType* any_cast(any*);

  template<typename ValueType>
  friend ValueType* unsafe_any_cast(any *);

  placeholder* content;
};

class bad_any_cast : public std::bad_cast
{
public:
  char const* what() const throw()
  {
    return "bad_any_cast: failed conversion using any_cast";
  }
};

template<typename ValueType>
inline ValueType* unsafe_any_cast(any* operand)
{
  return &static_cast<any::holder<ValueType>*>(operand->content)->held;
}

template<typename ValueType>
inline ValueType const* unsafe_any_cast(any const* operand)
{
  return unsafe_any_cast<ValueType>(const_cast<any*>(operand));
}

template<typename ValueType>
inline ValueType* any_cast(any* operand)
{
  return operand && operand->type() == typeid(ValueType)
    ? &static_cast<any::holder<ValueType>*>(operand->content)->held
    : 0;
}

template<typename ValueType>
inline ValueType const* any_cast(any const* operand)
{
  return any_cast<ValueType>(const_cast<any*>(operand));
}

template<typename ValueType>
inline ValueType any_cast(any& operand)
{
  typedef typename std::remove_reference<ValueType>::type nonref;

#ifndef NDEBUG
  nonref* result(any_cast<nonref>(&operand));
  if (!result)
    throw bad_any_cast();
  return *result;
#else
  return *unsafe_any_cast<nonref>(&operand);
#endif // NDEBUG
}

template<typename ValueType>
inline ValueType any_cast(any const& operand)
{
  typedef typename std::remove_reference<ValueType>::type nonref;

  return any_cast<nonref const&>(const_cast<any&>(operand));
}

#endif // ANY_HPP
share|improve this question
You mention unique_ptr. Why is content not a unique_ptr? – Konrad Rudolph Sep 2 '12 at 12:05
because unique_ptr is a class template. The different instantiations of it differ in type. But any, just like boost::any, can store any type. – user1095108 Sep 2 '12 at 22:37
@user1095108: No he means that instead of placeholder* content you can use unique_ptr<placeholder> content. It will make your life much easier. – user1131467 Dec 31 '12 at 12:05
It would make for prettier, but also heavier, code. – user1095108 Jan 1 at 17:10

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.