Reputation: 10415
So, I basically want to "add" extra stuff to the class, depending on what template arguments its being used with and then aliasing it for nicer interface. Something like this:
template<typename T, std::size_t N>
struct basic_foo
{
T data[N];
};
//what you see as comments is what i tried
template<> //template<typename T, std::size_t N>
struct basic_foo<double, 3> //: public basic_foo<T, N>
{
void foo_fun()
{
std::cout << "I'm a foo function!";
for (auto i : data) std::cout << i << " ";
}
};
template<> //template<typename T, std::size_t N>
struct basic_foo<int, 2> //: public basic_foo<T, N>
{
void bar_fun()
{
std::cout << "I'm a bar function!";
for (auto i : data) std::cout << i << " ";
}
};
using foo = basic_foo<double, 3>;
using bar = basic_foo<int, 2>;
int main()
{
foo a = { 12.0, 2.4, 3.0 };
bar b = { 1, 2 };
}
The problem is that I can't access data
in the specializations.
Is there a way to do this? Or should I rethink my structural decisions?
Upvotes: 2
Views: 990
Reputation: 19607
Your code, as it is now does not compile, because you don't have data
member in your specializations. You have tried to inherit it from the primary template, and you almost got it.
Make a basic_foo_base
class (or struct
) template, where you store data
and functions that needn't be specialized:
template <typename T, std::size_t N>
struct basic_foo_base
{
T data[N];
};
That was just adding _base
to the name of the existing definition. Now, define basic_foo
again:
template <typename T, std::size_t N>
struct basic_foo : basic_foo_base<T, N>
{
};
And this is how a specialization will look:
template <>
// instantiate the base with the same template arguments
struct basic_foo<double, 3> : public basic_foo_base<double, 3>
{
};
I hope I got everything right.
Edit: No, I didn't.
Because of inheritance, basic_foo
won't be an aggregate anymore. We'll need to add some code, so the initialization:
foo a = { 12.0, 2.4, 3.0 };
is valid again. That is, defining an implicit constructor taking std::initializer_list
:
basic_foo_base(std::initializer_list<T> const& il)
{
std::copy(il.begin(), il.end(), std::begin(data));
}
And adding
using basic_foo_base::basic_foo_base;
// or, for the primary template:
using basic_foo_base<T, N>::basic_foo_base;
in all basic_foo
s to include that constructor to the overload resolution.
Upvotes: 2
Reputation: 217135
Alternatively to common base class which contain data
, you may fully specialize:
template<>
struct basic_foo<double, 3>
{
double data[3]; // Should be here.
void foo_fun()
{
std::cout << "I'm a foo function!";
for (auto i : data) std::cout << i << " ";
}
};
Upvotes: 1