Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you write a copy constructor for a union with const members?

Tags:

c++

unions

Suppose I have a struct that contains a union with const members, like so:

struct S
{
  // Members

  const enum { NUM, STR } type;

  union
  {
    const int a;
    const std::string s;
  };

  // Constructors

  S(int t_a) : type(NUM), a(t_a);

  S(const std::string & t_s) : type(STR), s(t_s);

};

So far, so good. But now say I want to write a copy-constructor for this type.

It doesn't seem like this involves doing anything nefarious, but since I need to initialize the const members in member initializers I don't see how to do this based on logic that depends on the type member.

Questions:

  • Is it possible to write this constructor?

  • If not, is this essentially a syntactic oversight, or is there some fundamental reason that the language can't support such a thing?

like image 451
Daniel McLaury Avatar asked Feb 12 '19 20:02

Daniel McLaury


People also ask

Can unions have constructors?

A union can have member functions (including constructors and destructors), but not virtual functions.

Which options are valid for calling a copy constructor?

In C++, a Copy Constructor may be called for the following cases: 1) When an object of the class is returned by value. 2) When an object of the class is passed (to a function) by value as an argument. 3) When an object is constructed based on another object of the same class.

Can we use string in union?

Defining a Union union Data { int i; float f; char str[20]; } data; Now, a variable of Data type can store an integer, a floating-point number, or a string of characters. It means a single variable, i.e., same memory location, can be used to store multiple types of data.

Can a copy constructor have multiple arguments?

A copy constructor has as its first parameter a (possibly const or volatile) reference to its own class type. It can have more arguments, but the rest must have default values associated with them.


1 Answers

Yes, it is possible to write copy constructor here. Actually it is already done inside std::variant implementation, which shall support const-types among others. So your class S can be replaced with

using S = std::variant<const int, const std::string>;

But if for dome reason you cannot use std::variant then copy-constructor can be written using std::construct_at function as follows:

#include <string>

struct S {
  const enum { NUM, STR } type;

  union {
    const int a;
    const std::string s;
  };

  S(int t_a) : type(NUM), a(t_a) {}
  S(const std::string & t_s) : type(STR), s(t_s) {}
  S(const S & rhs) : type(rhs.type) {
      if ( type == NUM ) std::construct_at( &a, rhs.a );
      if ( type == STR ) std::construct_at( &s, rhs.s );
  }
  ~S() {
      if ( type == STR ) s.~basic_string();
  }
};

int main() {
    S s(1);
    S u = s;

    S v("abc");
    S w = v;
}

Demo: https://gcc.godbolt.org/z/TPe8onhWs

like image 180
Fedor Avatar answered Oct 18 '22 11:10

Fedor