2
votes

I have a pure virtual function that returns std::array in the base class. I want this array's size to be dependent on a type in the derived class. I've tried the following but it seems like the compiler can't resolve the templates due to incomplete type.

template<typename T>
struct base
{
    virtual std::array<int, T::SIZE> foo(void) = 0;
};

struct derived : public base<derived>
{
    enum 
    {
        SIZE = 5
    };
    std::array<int, derived::SIZE> foo(void) 
    {
        return std::array<int, derived::SIZE>{1,2,3,4,5};
    };
};

In instantiation of 'struct base': 12:25: required from here 9:38: error: incomplete type 'derived' used in nested name specifier

I have also tried doing something like a type trait but I get incomplete type again which in this case it makes sense since the template specialization needs the class to be actually complete before it can complete specialization.

template<typename T>
struct sizeTrait;

template<typename T>
struct base
{
    virtual std::array<int, sizeTrait<T>::SIZE> foo(void) = 0;
};

struct derived : public base<derived>
{
    std::array<int, sizeTrait<derived>::SIZE> foo(void) 
    {
        return std::array<int, sizeTrait<derived>::SIZE>{1,2,3,4,5};
    };
};

template<>
struct sizeTrait<derived>
{
    enum
    {
        SIZE = 5
    };
};

Does anyone have any idea on how to achieve something like this? I don't want to resort to using macros if possible. I plan on having many different types of derived classes which all inherit the base class but foo will return different sizes of std::array depending on the enum (or some other type) defined in their own class. Also, I know I can use a std::vector but I would like to do this using an array since the size of the output is determined already.

EDIT:

A suggestion was given to use a template parameter in base to determine the array size.

#include <array>

template<typename T, size_t S>
struct base
{
    using array_type = std::array<int, S>;
    virtual array_type foo() = 0;
};

struct derived : public base<derived, 5>
{
    array_type foo() override
    {
        return array_type {1, 2, 3, 4, 5};
    };
};

However, I have another templated class that takes derived as a template argument and it needs to have an array of the same size.

template<typename DerivedClass>
struct other
{
    std::array<int, DerivedClass::SIZE> array_;
};

In this case, I would like array_'s size to be determined based on what DerivedClass actually is. Is there a way to resolve that DerviedClass::SIZE was 5? Maybe access the base through the template parameter DerivedClass like DerivedClass::base::array_type?

2
Just a suggestion: make it complete so it'll be easy to copy/compile/dwell.Ted Lyngmo
Do you need base at all? If the only thing it contains is foo then it's useless.n. 1.8e9-where's-my-share m.
Do you intend to derive further from derived? If not, then making that function virtual is entirely pointless.StoryTeller - Unslander Monica
base has some functions that I wanted each derived to inherit and those functions operate based on the derived's "SIZE"Andy Tan

2 Answers

2
votes

In your sizeTrait attempt, you just need to move its definition ahead of its usage in derived. You accomplish that with a forward declaration of derived:

template<typename T>
struct sizeTrait;

template<typename T>
struct base
{
    virtual std::array<int, sizeTrait<T>::SIZE> foo(void) = 0;
};

struct derived;

template<>
struct sizeTrait<derived>
{
    enum
    {
        SIZE = 5
    };
};

struct derived : public base<derived>
{
    std::array<int, sizeTrait<derived>::SIZE> foo(void) 
    {
        return std::array<int, sizeTrait<derived>::SIZE>{1,2,3,4,5};
    }
};
1
votes

Why not make the size a template parameter on base?

#include <array>

template<typename T, size_t S>
struct base
{
    using array_type = std::array<int, S>;
    virtual array_type foo() = 0;
};

struct derived : public base<derived, 5>
{
    array_type foo() override
    {
        return array_type {1, 2, 3, 4, 5};
    }
};

Update to answer the question of getting access to the array type (or size) from classes using derived. You can just access the type:

template<class T>
struct another
{
    using array_type = typename T::array_type;

    array_type bar()
    {
        return array_type {1, 2, 3, 4, 5};
    }

    static constexpr size_t size()
    {
        // Returns 5
        return std::tuple_size<array_type>();
    }
};