Reputation: 3070
I have a class Foo
that operates that need a reference to be built (it will be used to work on that memory space)
template<typename T>
class Foo {
public:
Foo(T& value) : _value(value) {}
...
private:
T& _value;
};
I also have a linear memory space of multiple instances of T
std::array<T, SIZE> buffer;
What I'd like to build is an array of object of type Foo
which maps the differents instances of my buffer. Which means each instance of Foo
has to be built using the correct reference.
std::array<Foo<T>, SIZE> operators;
Still, operators
is cannot be trivially initialize, and I can manage to build it by 'mapping' the buffer through the 'Foo' constructor.
Is there any way to do ? I tried using std::forward
and std::initializer_list
but those cannot be constructed from my buffer.
Note that I need my buffer to stay aligned for communication purposes, and I will en up overloading the Foo
class to implement different behaviour for different elements of my array.
Upvotes: 3
Views: 117
Reputation: 1863
std::array
must know on initialization how to construct the references. Prefer using a pointer like this:
template<typename T>
class Foo {
public:
Foo() { } // used by std::array to create Foo<T>
Foo(T& value) : _value(&value) {}
operator T&() { return *_value; } // never call this on uninitialised objects
private:
T* _value = nullptr;
};
What you can do is to create a static object to pre-initialze your reference.
template<typename T>
class Foo {
static T _default; // default-object used to initialize the reference
public:
Foo() { } // used by std::array to create Foo<T>
Foo(T& value) : _value(value) {}
T& _value = _default;
};
int a = 0;
std::array<Foo<int>, 10> arr;
arr[0]._value = a;
Upvotes: 2
Reputation: 64308
Here's an example of how to use the indices trick to build your array:
#include <array>
#include <iostream>
template<typename T>
class Foo {
public:
Foo(T& value) : _value(value) {}
...
private:
T& _value;
};
// Typical varadic indices builder
template<size_t... Is> struct Indices { };
template <size_t count,size_t... Is>
struct BuildIndices : BuildIndices<count-1,count-1,Is...> { };
template<size_t... Is>
struct BuildIndices<0,Is...> : Indices<Is...> { };
// Helper function
template <typename T,size_t... Is>
static std::array<Foo<T>,sizeof...(Is)>
make_foo_array_with_indices(
std::array<T,sizeof...(Is)> &values,
Indices<Is...>
)
{
return {{values[Is]...}};
}
template <typename T,size_t count>
static std::array<Foo<T>,count>
make_foo_array(std::array<T,count> &values)
{
return make_foo_array_with_indices(values,BuildIndices<count>());
}
int main()
{
std::array<int,4> buffer = {3,1,4,1};
std::array<Foo<int>,4> operators = make_foo_array(buffer);
}
Upvotes: 0
Reputation: 409166
Unfortunately there is no way to directly initialize the operators
array.
The only solution I can think of is to make Foo
default constructible, and then loop over buffer
(using a loop or e.g. std::transform
) and "initialize" each entry in operators
using assignment.
Something like
template<typename T, std::size_t N>
void initialize_operators(const std::array<T, N>& buff,
std::array<Foo<T>, N>& ops)
{
std::transform(std::begin(buf), std::end(buff), std::begin(ops),
[](const T& t) { return Foo<T>(t); });
}
Upvotes: 1
Reputation: 477000
One way is to spell out the initializer elements:
T a, b;
std::array<Foo<T>, 5> a = { {
Foo<T>(a), Foo<T>(b), Foo<T>(a), Foo<T>(b), Foo<T>(a) } };
Another way would be to separate storage from object construction and manage the array element lifetimes manually.
Upvotes: 0