简体   繁体   中英

How to unravel type dependency? (X uses undefined class Y)

I'm trying to implement simplistic fast memory management for my delegate type, but encountered circular dependency which I can't solve myself.

// Size of single bucket of delegates
static constexpr size_t _alloc_buffer_bucket_size = 128;

template <typename TFunc, typename... Args>
struct bucket;

template <typename TFunc, typename... Args>
class Delegate final : public IDelegate
{   
    . . .

    static void* operator new (size_t size)
    {
        auto bckt = _current_bucket; // gives compilation error here
    }
private:

    // Size of single bucket of delegates
    static constexpr size_t _alloc_buffer_bucket_size = 128;
    struct bucket
    {
        // stores currently occupied slots in bucket.
        size_t allocated_slots = 0;
        // when this bucket is filling with values, this 
        size_t current_slot = 0;
        std::array<Delegate<TFunc, Args...>, _alloc_buffer_bucket_size> slots = {};
    };
    // Vector of buckets.
    inline static std::vector<bucket*> _alloc_buffer = { new bucket(), };
    // This is a pointer to currently filling bucket. New delegates are added here
    // by delegate allocator.
    // When this bucket reaches _alloc_buffer_bucket_size of items, this pointer is
    // replaced with either newly allocated bucket or existing and empty bucket.
    inline static bucket* _current_bucket = &(_alloc_buffer[0]);
};

This gives me " 'Delegate<void (*)(void)>::bucket::slots' uses undefined class 'std::array<Delegate<void (*)(void)>,128>' ". How can I break this circular dependency? I've tried using more pointers, moving bucket outside of Delegate scope, but this error remains.

By moving the definition of the bucket struct outside of the scope of Delegate and assigning the _alloc_buffer and _current_bucket variables outside of the class scope, we can achieve compilation. I was able to get it compiling as such:

// Size of single bucket of delegates
static constexpr std::size_t _alloc_buffer_bucket_size = 128;

template <typename TFunc, typename... Args>
struct bucket;

template <typename TFunc, typename... Args>
class Delegate final : public IDelegate
{
public:
    Delegate() = default;
    static void* operator new (std::size_t size)
    {
        auto bckt = _current_bucket; // gives compilation error here
        return nullptr; // added to get rid of the error
    }
private:
    // Vector of buckets.
    static std::vector<bucket<TFunc, Args...>*> _alloc_buffer;
    // This is a pointer to currently filling bucket. New delegates are added here
    // by delegate allocator.
    // When this bucket reaches _alloc_buffer_bucket_size of items, this pointer is
    // replaced with either newly allocated bucket or existing and empty bucket.
    static bucket<TFunc, Args...>* _current_bucket;
};

template <typename TFunc, typename... Args>
struct bucket
{
    // stores currently occupied slots in bucket.
    std::size_t allocated_slots = 0;
    // when this bucket is filling with values, this 
    std::size_t current_slot = 0;
    std::array<Delegate<TFunc, Args...>, _alloc_buffer_bucket_size> slots = {};
};

template <typename TFunc, typename... Args> 
std::vector<bucket<TFunc, Args...>*> Delegate<TFunc, Args...>::_alloc_buffer = { new bucket<TFunc, Args...>(), };

template <typename TFunc, typename... Args> 
bucket<TFunc, Args...>* Delegate<TFunc, Args...>::_current_bucket = &(_alloc_buffer[0]);

By splitting up the declaration and definition of the static variables and by splitting out the bucket type, the Delegate class is defined by the time we go to actually use it. See it in action here: https://godbolt.org/z/bx7hh1av9

Edit: Tested this minimum sample on MSVC and Clang.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM