Take the 2-minute tour ×
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 <cassert>

#include <stdexcept>

#include <typeinfo>

#include <type_traits> 

#include <utility>

namespace generic
{

class any
{
public:
  any() noexcept : content(nullptr) { }

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

  any(any&& other) noexcept { *this = std::move(other); }

  template<typename ValueType,
    typename = typename std::enable_if<
      !std::is_same<any, typename std::decay<ValueType>::type>::value
    >::type
  >
  any(ValueType&& value)
    : content(new holder<typename std::remove_reference<ValueType>::type>(
        std::forward<ValueType>(value)))
  {
  }

  ~any() { delete content; }

public: // modifiers

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

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

  any& operator=(any&& rhs) noexcept
  {
    content = rhs.content;
    rhs.content = nullptr;

    return *this;
  }

  template<typename ValueType,
    typename = typename std::enable_if<
      !std::is_same<any, typename std::remove_const<
        typename std::remove_reference<ValueType>::type>::type>::value
    >::type
  >
  any& operator=(ValueType&& rhs)
  {
    return *this = any(std::forward<ValueType>(rhs));
  }

public: // queries

  explicit operator bool() const noexcept { return content; }

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

private: // types

  struct placeholder
  {
    placeholder() = default;

    virtual ~placeholder() noexcept { }

    virtual placeholder* clone() const = 0;

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

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

    holder& operator=(holder const&) = delete;

    placeholder* clone() const final { throw std::invalid_argument(""); }

  public: // queries
    std::type_info const& type() const noexcept { 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 noexcept { return typeid(ValueType); }

  public:
    ValueType held;
  };

private: // representation

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

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

  placeholder* content;
};

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

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

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

template<typename ValueType>
inline ValueType const* any_cast(any const* const operand) noexcept
{
  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* const result(any_cast<nonref>(&operand));

  if (!result)
  {
    throw std::bad_cast();
  }
  // else do nothing

  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. –  user1131146 account abandoned Dec 31 '12 at 12:05
    
It would make for prettier, but also heavier, code. –  user1095108 Jan 1 '13 at 17:10
    
How concerned are you with the accuracy of your clone? It seems to be missing the empty and clear member functions, but I'm not sure how much you care (if at all). –  Jerry Coffin Mar 5 at 3:56
show 4 more comments

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.