I have a virtual class BASE
, and an inherited class BOX_str
which implements the virtual functions
class BASE {
public:
virtual ~BASE() {};
virtual std::vector<int> custom_int() const = 0;
virtual std::vector<double> custom_double() const = 0;
};
struct BOX_str final : public BASE {
template <typename ...Args>
BOX_str(Args... args) : base(std::forward<Args>(args)...) {}
std::string base;
std::vector<int> custom_int() const {
return custom_vec<int>(base);
}
std::vector<double> custom_double() const {
return custom_vec<double>(base);
}
template <typename NUM>
std::vector<NUM> custom_vec(const std::string& s) const {
return {32, 62};
}
};
But all of the BOX_str
class content, except for the custom_vec()
function, is generic amongst similar classes,
so I've tried to make a template class BOX
template <typename T>
struct BOX : public virtual BASE {
template <typename ...Args>
BOX(Args... args) : base(std::forward<Args>(args)...) {}
T base;
std::vector<int> custom_int() const {
return custom_vec<int>(base);
}
std::vector<double> custom_double() const {
return custom_vec<double>(base);
}
template <typename NUM>
std::vector<NUM> custom_vec(const T&) const;
};
and leave custom_vec()
to be implemented later for each explicit specialization of BOX
template <>
struct BOX<std::string> {
template <typename NUM>
std::vector<NUM> custom_vec(const std::string& s) const {
return {42, 52};
}
};
then I tried to test the classes
int main() {
std::string mystr{ "abcd" };
BASE* v1 = static_cast<BASE*>(new BOX<std::string>(mystr));
BASE* v2 = static_cast<BASE*>(new BOX_str(mystr));
}
v2
didn't raise any errors, but v1
did: excess elements in struct initializer
, which means the the explicit specialization of BOX
cannot access its constructor, and all of BOX
's contents.
I'm quite stuck and can't figure out how to correctly implement the BOX
class so that it would work like BOX_str
but in a generic manner. Would appreciate some assistance.
As always, any problem* can be solved by an additional abstraction layer:
Define BOX::custom_vec
to call a yet-to-be-defined ::custom_vec
:
template <typename T>
struct BOX : public virtual BASE {
// [...]
template <typename NUM>
std::vector<NUM> custom_vec(const T& v) const {
return ::custom_vec<T, NUM>{}(v);
}
Then, provide a struct that can be specialized and fully redefined without useless duplication of code:
template<class BoxT, class BoxN>
struct custom_vec {};
template<>
struct custom_vec<std::string, int>
{ std::vector<int> operator()(std::string const&) const { return {42, 52}; } };
template<>
struct custom_vec<std::string, double>
{ std::vector<double> operator()(std::string const&) const { return {1.618, 3.14}; } };
*except having too many abstraction layers