Search code examples
c++stdvectorunions

Appending to vector of union


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


Solution

  • 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.