2
\$\begingroup\$
#ifndef ANY_H
#define ANY_H

#include <typeinfo>

namespace _notYourNp
{
    struct BaseHolder
    {
        BaseHolder()
        {}

        virtual ~BaseHolder()
        {}

        virtual BaseHolder* clone() = 0;
    };

    template <class T>
    struct Holder : BaseHolder
    {
        Holder(const T& type)
            : m_Content(type)
        {}

        ~Holder()
        {       
        }

        BaseHolder* clone()
        {
            BaseHolder* tmpHolder = new Holder<T>(m_Content);

            return tmpHolder;
        }

        T m_Content;
    };
}

namespace exception
{
    class bad_cast_any
    {};
}

 class Any
 {
 public:

     Any()
        : m_Content(0), m_Type(const_cast<std::type_info*>(&typeid(int)))
     {}

     ~Any()
     {
         if (0 != m_Content)
         {
             delete m_Content;
         }
     }

    template <class T>
    operator T()
    {
        if (const_cast<std::type_info*>(&typeid(T)) != m_Type)
        {
            throw exception::bad_cast_any();
        }

        return static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content;
    }

    template<class T>
    Any(const T& value)
        : m_Content(0), m_Type(const_cast<std::type_info*>(&typeid(T)))
    {
        if(0 == m_Content)
        {
            m_Content = new _notYourNp::Holder<T>(value);
        }

        if (const_cast<std::type_info*>(&typeid(T)) != m_Type)
        {
            m_Type = const_cast<std::type_info*>(&typeid(T));

            if (0 != m_Content)
            {
                delete m_Content;
            }

            m_Content = new _notYourNp::Holder<T>(value);
        }
        else
        {
            static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content = value;
        }
    }

    Any(const Any& A)
        : m_Content(0), m_Type(0)
    {
        if (0 != m_Content)
        {
            delete m_Content;
        }
        m_Content = A.m_Content->clone();
        m_Type = A.m_Type;
    }

     template<class T>
     T& operator = (const T& value)
     {
        if(0 == m_Content)
        {
            m_Content = new _notYourNp::Holder<T>(value);
        }

        if (const_cast<std::type_info*>(&typeid(T)) != m_Type)
        {
            m_Type = const_cast<std::type_info*>(&typeid(T));

            if (0 != m_Content)
            {
                delete m_Content;
            }

            m_Content = new _notYourNp::Holder<T>(value);
        }
        else
        {
            static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content = value;
        }

        return static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content;
     }

    Any& operator = (const Any& value)
     {
        if (0 != m_Content && value.m_Type != m_Type)
        {
            delete m_Content;
        }

        m_Content = value.m_Content->clone();
        m_Type = value.m_Type;

        return *this;
     }

     template<class T>
     T& get()
     {
        if (const_cast<std::type_info*>(&typeid(T)) != m_Type)
        {
            throw exception::bad_cast_any();
        }

        return static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content;
     }

 private:

    std::type_info* m_Type;
     _notYourNp::BaseHolder* m_Content;
 };

 template<class T>
 T any_get(Any& any)
 {
     return any.get<T>();
 }

template<class from, class to>
to any_cast(Any& any)
{
    return static_cast<to>(static_cast<from>(any));
}

#endif

This is my try of an Any class. I would like to have some opinions about it.

Maybe I can answer one questions about the _notYourNp namespace before:

I just used it to hide the holder structs from the user and I didn't wanted them in my any class itself (so the name makes no sense --> not your namespace private). I know it's not the best idea I'm working on a better one, and yes I took some ideas from any (Like the name any and the naming any_cast<>).

I hope for some ideas, opinions (also bad ones if there are some), but please, if you bring criticism, then only constructive (and yes throw it away is also constructive criticism).

I tried it on vc10, 13 and the cpp droid compiler for Android.

As accurate as I can measure it (by using int = time start //Code\ time stop) it is surprising fast compared to boost::any, I don't know why maybe there is a mistake anywhere.

Usage example:

int main()
{
    Any var;
    var = 5;

    int i = var;
    double d = any_cast<int, double>(var);

    std::vector<Any> v;
    v.push_back(5);
    int z = v.at(0);

    return 0;
}

EDIT***** Additional here is how I measured the speed for assigning and reading from my any (not very accurate how I already wrote, but enough to get a relation)

    int placeholder;
    double otherPlaceholder;

    clock_t start, end;
    double cpu_time_used;

    start = clock();
    for (unsigned int i = 0; RUNTIMES > i; ++i)
    {
        placeholder = any; //bzw for boost: placeholder = boost::any_cast<int>(any);
        //and for boost::variant: boost::get<int(variant);
    }

    //measuring the speed for getting the value from any
    //for (unsigned int i = 0; RUNTIMES > i; ++i)
    //{
    //  any = placeholder;
    //  any = otherPlaceholder;
    //}

    end = clock();
    cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;

    //the 3000000 or 6000000 to get a 0.xx value
    double timing = (cpu_time_used / RUNTIMES) / 3000000
    //double timing = (cpu_time_used / RUNTIMES) / 6000000 for reading speed

The performance testing code is not written by me! So no questions about it to me please (https://stackoverflow.com/questions/795827/testing-the-performance-of-a-c-app).

And this are the results saved in a log.txt

mango::Any assign reference timing: 0.8075 x 10 power( - 6 ) seconds
mango::Any get value reference timing: 0.0466667 x 10 power( - 6 ) seconds
boost::any assign reference timing: 0.931667 x 10 power( - 6 ) seconds
boost::any get value reference timing: 0.353333 x 10 power( - 6 ) seconds
boost::variant assign reference timing: 2.0225 x 10 power( - 6 ) seconds
boost::variant get value reference timing: 0.465 x 10 power( - 6 ) seconds

And here is my newer version of Any

#ifndef ANY_H
#define ANY_H

#include <typeinfo>

namespace mango
{
    namespace exception
    {
        class bad_cast
        {};
    }

namespace detail
{
    template <class T> void killContent(void* target);
    template <class T> void reproduceAny(void* target, void*& pool);
}

class Any
{
public:

    Any()
        : m_Content(new int), m_ContentType(const_cast<std::type_info*>(&typeid(int))), kill(&detail::killContent<int>), reproduceAnyContent(&detail::reproduceAny<int>)
    {}

    ~Any()
    {
        if (nullptr != m_Content)
        {
            kill(m_Content);
        }
    }

    template<class T>
    operator T&()
    {
        if (const_cast<std::type_info*>(&typeid(T)) != m_ContentType)
        {
            throw exception::bad_cast_any();
        }

        return *static_cast<T*>(m_Content);
    }

    template<class T>
    Any(const T& value)
        : m_Content(new T(value)), m_ContentType(const_cast<std::type_info*>(&typeid(T))), kill(&detail::killContent<T>), reproduceAnyContent(&detail::reproduceAny<T>)
    {
        if (nullptr == m_Content)
        {
            m_Content = new T(value);

            kill = &detail::killContent<T>;
            reproduceAnyContent = &detail::reproduceAny<T>;
        }

        if (const_cast<std::type_info*>(&typeid(T)) != m_ContentType)
        {
            m_ContentType = const_cast<std::type_info*>(&typeid(T));

            if (nullptr != m_Content)
            {
                kill(m_Content);
            }

            m_Content = new T(value);

            kill = &detail::killContent<T>;
            reproduceAnyContent = &detail::reproduceAny<T>;
        }
        else
        {
            *static_cast<T*>(m_Content) = value;
        }
    }

    Any(const Any& C)
        : m_Content(nullptr), m_ContentType(nullptr), kill(nullptr), reproduceAnyContent(nullptr)
    {
        if (nullptr != m_Content)
        {
            kill(m_Content);
        }

        reproduceAnyContent(C.m_Content, m_Content);

        kill = C.kill;
        reproduceAnyContent = C.reproduceAnyContent;

        m_ContentType = C.m_ContentType;
    }

    template<class T>
    T& operator = (const T& value)
    {
        if (nullptr == m_Content)
        {
            m_Content = new T(value);

            kill = &detail::killContent<T>;
            reproduceAnyContent = &detail::reproduceAny<T>;
        }

        if (const_cast<std::type_info*>(&typeid(T)) != m_ContentType)
        {
            m_ContentType = const_cast<std::type_info*>(&typeid(T));

            if (nullptr != m_Content)
            {
                kill(m_Content);
            }

            m_Content = new T(value);

            kill = &detail::killContent<T>;
            reproduceAnyContent = &detail::reproduceAny<T>;
        }
        else
        {
            *static_cast<T*>(m_Content) = value;
        }

        return *static_cast<T*>(m_Content);
    }

    Any& operator = (const Any& value)
    {
        if (nullptr != m_Content)
        {
            kill(m_Content);
        }

        reproduceAnyContent(value.m_Content, m_Content);

        kill = value.kill;
        reproduceAnyContent = value.reproduceAnyContent;

        m_ContentType = value.m_ContentType;

        return *this;
    }

    template<class T>
    T& get()
    {
        if (const_cast<std::type_info*>(&typeid(T)) != m_ContentType)
        {
            throw exception::bad_cast_any();
        }

        return *static_cast<T*>(m_Content);
    }

private:
    void* m_Content;
    std::type_info* m_ContentType;

    void(*kill)(void* target);
    void(*reproduceAnyContent)(void* target, void*& pool);
};

template<class T>
T any_get(Any& any)
{
    return any.get<T>();
}

template<class from, class to>
to any_cast(Any& any)
{
    return static_cast<to>(static_cast<from>(any));
}

namespace detail
{
    template <class T>
    void killContent(void* target)
    {
        delete static_cast<T*>(target);
    }

    template <class T>
    void reproduceAny(void* target, void*& pool)
    {
        pool = new T(*static_cast<T*>(target));
    }
}
}

#endif //Any_H
\$\endgroup\$
3
\$\begingroup\$
  • Your class Any class should be in a namespace. Don't pollute the global namespace.
  • Your struct Holder and struct BaseHolder should be private internal classes of Any. Don't deliberately confuse people.
  • I note that your Holder::clone() does a shallow copy. Is this your intention?
  • Use NULL or (better) nullptr instead of 0. The C++ standard does not guarantee that 0 is a synonym of NULL. This makes it clear that you mean a null pointer instead of a number, gets rid of a possible "magic number", doesn't involve any typecasting (implicit or explicit).
\$\endgroup\$
  • \$\begingroup\$ Okay, the namespace around the any class is a good idea you are right but I would like to have a better solution than pack everything else inside the object. If i don't find any other possibilities I'm going to do what you said. The Holder::clone() function makes a deep copy of the value Holder::m_Content, it's not necessary to make a copy of m_Type, because typeinfo objects are unique so i just changed the pointer. Last but not least, I think NULL is good I'm going to change it. Thanks for your comment. \$\endgroup\$ – Mango May 4 '15 at 14:47
  • 1
    \$\begingroup\$ "The C++ standard does not guarantee that 0 is a synonym of NULL." It does. C doesn't and could be 0 or (void*)0. \$\endgroup\$ – edmz May 20 '15 at 15:21
  • \$\begingroup\$ In the newer version I choose nullptr but there is a little problem which I don't like on it, I think older compiler wich don't know C++11 won't compile it (my smartphone with CppDroid for example), so what would be an alternativ for older compiler? \$\endgroup\$ – Mango May 21 '15 at 6:28
  • \$\begingroup\$ By the way, boost::any solved this with 0 \$\endgroup\$ – Mango May 21 '15 at 6:56
  • \$\begingroup\$ @Mango #if __cplusplus >= 201103L #define nullptr nullptr #else #define nullptr 0 #endif . They've to be on separate lines though. \$\endgroup\$ – edmz May 31 '15 at 10:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.