Home > Software design >  Specialization doesn't contain data that's declared in the primary template
Specialization doesn't contain data that's declared in the primary template

Time:12-13

class Base {
public:
    virtual void load() = 0;
};

template<typename T>
class CustomConfig : public Base {
public:
    const T& getData() { return data; }
    T data;
};

template<>
class CustomConfig<std::set<uint32_t>> {
public:
    virtual void load() {
        this->data = {4, 5, 6};
    }
};

I don't know why I got the error:

class CustomConfig<std::set<unsigned int> >' has no member named 'data'

REAL CASE

In fact, I got such an issue: I need a virtual function, but it's return type is not unique, it may be a std::set, a std::vector, std::list or some other types. Then I was thinking the template technique might help. That's why I defined the class template<typename T> class CustomConfig.

I hope this was not a serious XY problem... Obviously I misunderstood how template class works.

CodePudding user response:

To provide an alternative to the other answers, which all say you must add your data member, there's another option which is to derive from a template instantiation instead:

class CustomConfigSetOfUInt : public CustomConfig<std::set<uint32_t>> {
public:
    void load() override {
        this->data = {4, 5, 6};
    }
};

If your CustomConfig provides other generalized functionality that would benefit from being done in the class template, then you might prefer this approach. Your design in general is a bit uncomfortable and does seem to have a "relaxed" attitude toward encapsulation either way. You may want to have a deeper think about it.

CodePudding user response:

The specialization is a brand-new class (relative to the primary template), you have to declare the data member for it too (also the inheritting). E.g.

template<>
class CustomConfig<std::set<uint32_t>> : public Base {
public:
    virtual void load() {
        this->data = {4, 5, 6};
    }
    const std::set<uint32_t>& getData() { return data; }
    std::set<uint32_t> data;
};

CodePudding user response:

CustomConfig<std::set<uint32_t>> is a specialization of CustomConfig<T>, ie it replaces CustomConfig<T> when T is std::set<uint32_t>, it does not derive from CustomConfig<T> like you are thinking. As such, it does not inherit any of the members of CustomConfig<T>.

The two are completely separate classes.

CodePudding user response:

That specialisation does not inherit from the template class, it is instead used in place of the templated class for a specific data type.

So it gets no data or load(), you have to provide them yourself, such as with:

template<>
class CustomConfig<std::set<uint32_t>> : public Base {
public:
    virtual void load() {
        this->data = {4, 5, 6};
    }
    const std::set<uint32_t> &getData() { return data; }
    std::set<uint32_t> data;
};

In any case, it's often a good idea to steer clear of more "generic" underlying types, as that can be a great assistance in discovering and repairing issues. By that, I mean something like type definitions to make things clearer:

using ConfigIntSet = std::set<uint32_t>; // Use *specific* type.
template<>
class CustomConfig<ConfigIntSet> : public Base {
public:
    virtual void load() {
        this->data = {4, 5, 6};
    }
    ConfigIntSet data;
};
  • Related