Home > Back-end >  Appending to vector of union
Appending to vector of union

Time:03-18

I have a union, defined like so:

union CellType {
    std::string str;
    int i;
    double d;
    Money<2> m;  // Custom class for fixed-decimal math.
};

Then, I have a vector of such unions.

std::vector<CellType> csvLine;

My question is, how do I append a value to the end of the vector? I normally use push_back for vectors of strings, ints, etc., but can't quite figure out the syntax when the vector elements are unions. Any help would be appreciated.

(Yes, this class is reading CSV files a line at a time, if that makes any difference.)

here is failing MRE

#include <vector>
#include <iostream>


union CellType {
    std::string str;
    int i;
    double d;
//    Money<2> m;  // Custom class for fixed-decimal math.
};
int main() {
    std::vector<CellType> csvLine;
    CellType c;
    c.str = "foo";
    csvLine.push_back(c);
}

Money commented out because because irrelevant to the MRE

Error

Severity Code Description Project File Line Suppression State Error C2280 'CellType::CellType(void)': attempting to reference a deleted function ConsoleApplication1 C:\work\ConsoleApplication1\ConsoleApplication1.cpp 22

CodePudding user response:

There is no clean way to do this for the simple reason that given an arbitrary instance of this union there is no authoritative way for a generic, template-based function/method, like std::vector::push_back to know which member of the union is active, in order to execute the member-specific copy/move operation, when at least one member of the union is not a POD. There's nothing inherent to any particular instance of a union that states "this specific union contains a std::string so to copy/move it you will use std::string's appropriate copy/move operator". C simply does not work this way, this is fundamental to C . There is no workaround, and no syntax for this.

In general, due to C 's foundation in type-safety, an inhererently type-unsafe union, when used together with non-POD members like std::string, produces an end result with quite limited capabilities.

The least amount of pain for you would be to replace your union with C 17's std::variant, a type-safe union. push_back then becomes a big, fat, nothing-burger.

CodePudding user response:

If you are using pre C 11 compiler then:

Unions cannot contain a non-static data member with a non-trivial special member function (copy constructor, copy-assignment operator, or destructor).

and std::string has non-trivial all of the above functions.

If you are using compiler which supports C 11:

If a union contains a non-static data member with a non-trivial special member function (copy/move constructor, copy/move assignment, or destructor), that function is deleted by default in the union and needs to be defined explicitly by the programmer.

If a union contains a non-static data member with a non-trivial default constructor, the default constructor of the union is deleted by default unless a variant member of the union has a default member initializer.

This basically means that you don't have any of the union constructors and you need to define copy or move constructor yourself for the following line to work:

csvLine.push_back(c);

as push_back method either copies or moves the object to its target location.

BTW, as far as I remember most (if not all) standard containers require that objects they contain are copy-constructible. Your union, as presented here in a question, isn't.

Source of the quotations: Union declaration

  • Related