HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcppMinor

Using std::array to implement variadic construction of class with list-of-self as subclass

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
stdimplementarraywithconstructionsubclassvariadicusinglistclass

Problem

I have a situation with a base class for whom a container of itself is a subclass. So a Block of Item has various ways in which it acts like an Item itself. I want to be able to initialize Block as Block {foo, baz, bar...} in a variadic syntax.

Here are the twists:

-
When a Block is constructed, the parameters in the initialization list are not simply Items. (Imagine some represent two items... while others might just be a different meaning for the literal types passed in.) To simplify the example I am suggesting that constructing an Item from a C-string literal is not available to the user... but that a Block initialization list would know what to do with that in context.

-
I'm trying to avoid creating std::vector in the course of the initialization, and instead building a std::array for as near-zero runtime overhead as I can get. Each element in the Block initialization should be constructed (or copy constructed) just once in the process; right in place in the array... though this array is only needed temporarily. As far as I can tell, this rules out std::initializer_list and I must use a variadic function.

The basic idea is to create a class that has containership of an Item which is a friend of Item... here called Listable. It has its own set of constructors:

class Item {
    friend class Listable; 
    friend class Block;
    Item (char const *) { std::cout  
    Block (std::array a) : Block (&a[0], N) { std::cout 
    Block (Ts const & ...t) : Block (std::array{t...})
        { std::cout << "B\n"; }
};


Here is a usage, showing a string not working for the construction of an Item while the Block knows how to handle it. The goodItem is the only one that needs to be copied, as its original instance was not constructed in-place in an array slot:

```
#include
#include

/ #include the classes above /

int main() {
auto goodItem = Item {10.20};
auto goodBlock = Block {goodItem, "blue", "red", 3.04};
/* auto m

Solution

I have a few things to say about your code:

-
Do you intend to actually do things in the constructors instead of just displaying strings? Knowing this would help the review process. Currently, you do not store anything passed to Item, but if you intend to store things at some point, it may change things.

-
Instead of using &a[0] which is kind of obscure and not easy to find with a simple search query, you shoud use a.data() which clearly shows the intent.

-
It would probably be a good idea to pass the std::array by const reference in the constructor instead of passing it by copy. That will avoid useless copies:

template 
Block (std::array const& a) : Block (&a[0], N) { cout << "Barray\n"; }


Of course, that implies that you take const Listable instead of Listable at some point (but we come back to my first point: we lack information about what your code is supposed to do). I don't know what you intend to do with this, but passing a pointer to the underlying memory of a temporary doesn't feel right. This may create dangling pointers.

EDIT: since your code isn't supposed to store the pointer, then taking the std::array by copy shoud be safe. But as you noted in the comments, using an rvalue-reference parameters should be even better: it binds to the temporary, you can modify it and no copy is performed. Seems like the best solution.

Code Snippets

template<size_t N> 
Block (std::array<Listable, N> const& a) : Block (&a[0], N) { cout << "Barray\n"; }

Context

StackExchange Code Review Q#72252, answer score: 6

Revisions (0)

No revisions yet.