Reputation: 6801
I wish to have a general template class that allows the user to pass the container to use:
template<class Container>
struct Sum
{
Container m_terms;
...
Other classes will derive from that, for example,
class MySum : public Sum<std::vector<int>>
{
...
or
class MySum4 : public Sum<std::array<int, 4>>
{
...
The containers need to be initialized from the constructor.
My idea at first was to use std::initializer_list
, for example,
MySum ms{1, 2, 3, 4};
which would require the following constructors to be added:
template<class Container>
struct Sum
{
Container m_terms;
Sum(std::initializer_list<typename Container::value_type> const& il) :
m_terms(il) { }
...
class MySum : public Sum<std::vector<int>>
{
using Sum<std::vector<int>>::Sum;
...
but then how can I get MySum4 to work too? An array
doesn't take a std::initializer_list<>
.
Here is more complete code that shows the compiler error: https://wandbox.org/permlink/CZW3YaKdInwZZD8e
Upvotes: 4
Views: 215
Reputation: 6801
For completeness I wanted to answer my own question with a method that I only realized later is possible; namely, simply allow the caller to pass the container (whose type it knows) as an rvalue. And to my surprise this then works with all containers when passing double braces!
struct Sum
{
Container m_terms;
Sum(Container&& terms) : m_terms(std::move(terms)) { }
void print()
{
for (auto&& term : m_terms)
std::cout << ' ' << term;
std::cout << std::endl;
}
};
And the DEMO
struct MySum : Sum<std::vector<int>>
{
MySum(int t0, int t1, int t2, int t3) : Sum<std::vector<int>>{{t0, t1, t2, t3}} { }
};
struct MySum4 : Sum<std::array<int, 4>>
{
MySum4(int t0, int t1, int t2, int t3) : Sum<std::array<int, 4>>{{t0, t1, t2, t3}} { }
};
struct MySumSet : Sum<std::set<int>>
{
MySumSet(int t0, int t1, int t2, int t3) : Sum<std::set<int>>{{t0, t1, t2, t3}} { }
};
struct MySumList : Sum<std::list<int>>
{
MySumList(int t0, int t1, int t2, int t3) : Sum<std::list<int>>{{t0, t1, t2, t3}} { }
};
int main()
{
MySum s(1, 2, 3, 4);
s.print();
MySum4 s4(1, 2, 3, 4);
s4.print();
static_assert(s4.m_terms.size() == 4);
MySumSet ss(1, 2, 3, 4);
ss.print();
MySumList sl(1, 2, 3, 4);
sl.print();
}
Upvotes: 1
Reputation: 2880
An alternative way is applying the variadic template with double braces for the ctor Sum::Sum
as follows.
This double braces enable us to set Container
to std::array
:
template<typename Container>
struct Sum
{
Container m_terms;
template<typename ...Args>
Sum(Args&&... args) : m_terms{{std::forward<Args>(args)...}} { }
void print()
{
for (auto&& term : m_terms){
std::cout << ' ' << term;
}
std::cout << std::endl;
}
};
Then you can do like this:
struct MySum : Sum<std::vector<int>>
{
MySum(int t0, int t1, int t2, int t3) : Sum<std::vector<int>>{t0, t1, t2, t3} { }
};
struct MySum4 : Sum<std::array<int, 4>>
{
MySum4(int t0, int t1, int t2, int t3) : Sum<std::array<int, 4>>{t0, t1, t2, t3} { }
};
struct MySumSet : Sum<std::set<int>>
{
MySumSet(int t0, int t1, int t2, int t3) : Sum<std::set<int>>{t0, t1, t2, t3} { }
};
struct MySumList : Sum<std::list<int>>
{
MySumList(int t0, int t1, int t2, int t3) : Sum<std::list<int>>{t0, t1, t2, t3} { }
};
int main()
{
MySum s(1, 2, 3, 4);
s.print();
MySum4 s4(1, 2, 3, 4);
s4.print();
static_assert(s4.m_terms.size() == 4);
MySumSet ss(1, 2, 3, 4);
ss.print();
MySumList sl(1, 2, 3, 4);
sl.print();
}
Upvotes: 1
Reputation: 66210
What about using old C-style arrays and delegating constructors?
Something as follows
template <typename T, std::size_t N, std::size_t ... Is>
Sum (T const (& il)[N], std::index_sequence<Is...> const)
: m_terms{{il[Is]...}}
{ }
template <typename T, std::size_t N>
Sum (T const (& il)[N]) : Sum(il, std::make_index_sequence<N>{})
{ }
But you have to add a couple of braces calling it
struct MySum : Sum<std::vector<int>>
{
MySum(int t0, int t1, int t2, int t3) : Sum<std::vector<int>>{{t0, t1, t2, t3}} { }
}; // ..........................................................^..............^
struct MySum4 : Sum<std::array<int, 4>>
{
MySum4(int t0, int t1, int t2, int t3) : Sum<std::array<int, 4>>{{t0, t1, t2, t3}} { }
}; // .............................................................^..............^
Upvotes: 1