0

Try to implement a tiny-any:

#include <iostream>
#include <type_traits>
#include <memory>

class TinyAny
{
public:
    template <typename Tp>
    TinyAny(Tp&& val) : data(std::make_shared<unsigned char[]>(sizeof(val))) {
        new(data.get()) Tp(std::forward<Tp>(val));
    }

    template <typename Tp>
    TinyAny &operator =(Tp&& val)
    {
        data = std::make_shared<unsigned char[]>(sizeof(val));
        new(data.get()) Tp(std::forward<Tp>(val));
        return *this;
    }

    template <typename Tp>
    Tp get()
    {
        return *reinterpret_cast<Tp *>(data.get());
    }
private:
    std::shared_ptr<unsigned char[]> data;
};


int main() {
    // var = "abc";
    // std::cout << var.get<const char *>() << std::endl;
}

if uncomment var = "abc" will get the fellowing error:

<source>: In instantiation of 'TinyAny& TinyAny::operator=(Tp&&) [with Tp = const char (&)[4]]':
<source>:40:11:   required from here
<source>:17:9: error: new cannot be applied to a reference type
   17 |         new(data.get()) Tp(std::forward<Tp>(val));
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<source>:17:44: error: invalid conversion from 'const char*' to 'char' [-fpermissive]
   17 |         new(data.get()) Tp(std::forward<Tp>(val));
      |                            ~~~~~~~~~~~~~~~~^~~~~
      |                                            |
      |                                            const char*

The type of val is const char*, but I cannot understand which one is char? Or, how can I fix this error?

Source Code: https://gcc.godbolt.org/z/zW7fPc6G3

BBing
  • 152
  • 5
  • 1
    You can refer to the [implementation of libstdc++](https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/any), it is not very complicated. – 康桓瑋 Jul 06 '22 at 03:14
  • @康桓瑋 Thanks, I had read the source code of `std::any`. I just want to implement a 'tiny-any' by normal memory which can be not type-safed or not highly-efficient. In fact, what confused me is the aboved error message. – BBing Jul 06 '22 at 03:36
  • 1
    Um, that's not at all what `std::any`'s interface is like. Copying the `any` will copy its contents, not merely reference a shared_ptr. And a "not type-safed" any is just a `void*` so... just use that. – Nicol Bolas Jul 06 '22 at 03:37
  • 1
    How is this supposed to behave? It will free the memory, but will not call the stored type's destructor. – user17732522 Jul 06 '22 at 06:28
  • 1
    The immediate problem is that you need to decide whether `var = "abc"` is supposed to cause `var` to store a `const char[4]` array or whether it is supposed to store a `char*`. If the former, you need some special cases, since the `new` expression doesn't work like this with an array type. If the latter, then you should `std::decay` the type when storing or retrieving. – user17732522 Jul 06 '22 at 06:30
  • @NicolBolas Yep, `void *` may better. – BBing Jul 06 '22 at 07:23
  • @user17732522 Sincerly thanks, it's neccessary to consider the stored type's destructor indeed. I decide `var = "abc"` supposed to store a `char *`, and had implement another edtion [https://gcc.godbolt.org/z/P6McGeKvs](https://gcc.godbolt.org/z/P6McGeKvs) – BBing Jul 06 '22 at 07:32
  • you can find some simple implementation [here](https://stackoverflow.com/q/51361606/995714) – phuclv Jul 26 '22 at 09:19

1 Answers1

0

My finally implement:

#include <type_traits>
#include <utility>

class TinyAny
{
    template<typename Tp>
    class AnyData {
    public:
        static void create(void **data, Tp && val)
        {
            *data = new Tp(std::forward<Tp>(val));
        }

        static void deleter(void *data)
        {
            auto ptr = static_cast<Tp *>(data);
            delete ptr;
        }
    };
public:
    template <typename Tp__, typename Tp = std::decay_t<Tp__>>
    TinyAny(Tp__&& val) : deleter(AnyData<Tp>::deleter) {
        AnyData<Tp>::create(&data, std::forward<Tp>(val));
    }

    ~TinyAny() {
        deleter(data);
        data = nullptr;
    }

    template <typename Tp>
    TinyAny &operator = (Tp&& val)
    {
        TinyAny temp{std::forward<Tp>(val)};
        swap(std::move(temp));
        return *this;
    }

    template <typename Tp>
    Tp get()
    {
        return *static_cast<Tp*>(data);
    }
private:
    TinyAny &swap(TinyAny && another) noexcept
    {
        std::swap(data, another.data);
        std::swap(deleter, another.deleter);
        return *this;
    }

private:
    void *data;
    void (* deleter)(void *data);
};
BBing
  • 152
  • 5