问题
In continuation of this topic Variadic template heterogeneous container, I would like to ask the following. Assume, that we have several classes with two members that is dynamic arrays. Now suppose that there is a sequence of objects of these classes, which is packed in heterogeneous container. In this sequence one of arrays-mebers is "output" vector and another array-member is "input" vector, which is pointer to appropriate output array from preceding object. This sequence is implemented as variadic template class:
//Classes, objects which are members of the sequence
template<int NumberElements>
struct A
{
A() : output(new float[NumberElements]){}//allocate output
~A(){delete[] output;}
float *input;//input vector - pointer to output vector from preceding object of sequence
float *output;// output vector (size - NumberElements) of current member of sequence
};
template<int NumberElements>
struct B
{
B() : output(new float[NumberElements]){}//allocate output
~B(){delete[] output;}
float *input;
float *output;
};
template<int NumberElements>
struct C
{
C() : output(new float[NumberElements]){}//allocate output
~C(){delete[] output;}
float *input;
float *output;
};
//Container
template<typename...Arg>
struct HeterogenousContainer
{
HeterogenousContainer();//Do something to setup the sequence
std::tuple<Arg...> elements;
};
How can I properly allocate memory (via new/malloc) for output vectors, and set up input pointers to preceding output vectors? For example, I write next code:
HeterogenousContainer<A<5>, B<7>, C<9>> sequence;
I want that input from first member of sequence to be nullptr, input from second - points to output from first, etc. How to implement it correctly?
回答1:
Inspired by Useless' answer (no pun intended), I came up with this:
template<typename...Arg>
struct HeterogenousContainer
{
std::tuple<Arg...> elements;
void init(std::integral_constant<std::size_t, 0>)
{
std::get<0>(elements).input = nullptr;
}
template < std::size_t index = sizeof...(Arg)-1 >
void init(std::integral_constant<std::size_t, index> = {})
{
std::get<index>(elements).input = std::get<index-1>(elements).output;
init(std::integral_constant<std::size_t, index-1>{});
}
HeterogenousContainer()
: elements{}
{
init();
}
};
回答2:
Firstly, don't mess around with manual (de)allocation if you can avoid it. For a simple array, you can:
#include <array>
#include <tuple>
template<int NumberElements>
struct A
{
float *input;
std::array<float, NumberElements> output;
};
You just need to recurse down the tuple, and specialize for the termination case. I'm doing it backwards since the first element is your special case.
namespace detail {
template <int N> struct Connector;
template <>
struct Connector<0> {
template <typename... TL> static void connect(std::tuple<TL...> &t) {
std::get<0>(t).input = nullptr;
}
};
template <int N> struct Connector {
template <typename... TL> static void connect(std::tuple<TL...> &t) {
std::get<N>(t).input = &std::get<N-1>(t).output.front();
Connector<N-1>::connect(t);
}
};
template <typename... TL> void connect(std::tuple<TL...> &t) {
Connector<sizeof...(TL)-1>::connect(t);
}
}
and use it something like this:
template <typename... Arg> struct HeterogenousContainer {
std::tuple<Arg...> elements;
HeterogenousContainer() { detail::connect(elements); }
};
来源:https://stackoverflow.com/questions/17934626/heterogeneous-sequence-generator