2

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?

4
  • 1
    Just a suggestion: make it complete so it'll be easy to copy/compile/dwell. Commented Nov 3, 2018 at 5:51
  • Do you need base at all? If the only thing it contains is foo then it's useless. Commented Nov 3, 2018 at 6:17
  • Do you intend to derive further from derived? If not, then making that function virtual is entirely pointless. Commented Nov 3, 2018 at 11:38
  • base has some functions that I wanted each derived to inherit and those functions operate based on the derived's "SIZE" Commented Nov 3, 2018 at 18:15

2 Answers 2

2

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};
    }
};
Sign up to request clarification or add additional context in comments.

Comments

1

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>();
    }
};

3 Comments

Thanks for the answer janm. I should have mentioned that I have another class with a template parameter that takes derived. I would like for this templated class to contain an array of the same size as the output array of derived. If I explicitly put a 5, is there anyway that I can determine the templated class's array size from the template parameter? I will update the question for a better description.
@AndyTan Updated. That's one of the reasons for just exposing the type. You don't have to type it everywhere, and it is explicit that the type comes from the base class.
Hi janm, your answer makes complete sense. Exposing the type allowed the size to be accessible in another and I was able to declare an array_type array in another like I intended. Great answer! Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.