1

There is a nice unanswered question about having union with const members: Can you write a copy constructor for a union with const members?

One of suggestions there is to use std::variant instead. Indeed, const types must be supported P0086 - Variant design review. The relevant paragraph says:

variant<int, const int> A variant can handle const types: they can only be set through variant construction and emplace().

So I assume variant copy construction must support them as well.

But an attempt to use this option:

#include <string>
#include <variant>

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

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

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

fails in GCC with a very long error (quote only its beginning here):

n file included from <source>:2:
/opt/compiler-explorer/gcc-trunk-20211024/include/c++/12.0.0/variant: In instantiation of 'constexpr std::__detail::__variant::_Variadic_union<_First, _Rest ...>::_Variadic_union(std::in_place_index_t<_Np>, _Args&& ...) [with long unsigned int _Np = 1; _Args = {const int&}; _First = const std::__cxx11::basic_string<char>; _Rest = {}]':
/opt/compiler-explorer/gcc-trunk-20211024/include/c++/12.0.0/variant:409:4:   required from 'constexpr std::__detail::__variant::_Variadic_union<_First, _Rest ...>::_Variadic_union(std::in_place_index_t<_Np>, _Args&& ...) [with long unsigned int _Np = 2; _Args = {const int&}; _First = const int; _Rest = {const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >}]'
/opt/compiler-explorer/gcc-trunk-20211024/include/c++/12.0.0/bits/stl_construct.h:119:7:   required from 'constexpr void std::_Construct(_Tp*, _Args&& ...) [with _Tp = std::__detail::__variant::_Variadic_union<const int, const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >; _Args = {const std::in_place_index_t<2>&, const int&}]'

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

Is there something wrong with my code, or GCC must accept it?

Fedor
  • 17,146
  • 13
  • 40
  • 131
  • 2
    The problem appeared after [libstdc++ implemented P2231R1](https://github.com/gcc-mirror/gcc/commit/ad820b0bb5f8342a8db2831d1f15c103583a3ba0#diff-42d34e2570773e3c256c114cc9371f613ed6fbb68be254f3ab008d872d630c6b), I very much suspect that this is a bug. – 康桓瑋 Oct 24 '21 at 11:29

1 Answers1

3

As noted in the comment above, the code only started to be rejected by GCC trunk very recently (and is accepted by all released versions of GCC), after I implemented P2231R1.

As I said in the bug report, before P2231R1 the libstdc++ std::variant was playing a bit fast and loose with constructing the active member of the union. After the P2231 changes we need to construct the correct union member, or it won't be valid in constexpr functions. That required some refactoring to be able to use the index of the member when constructing it.

It's fixed now, thanks for noticing the bug.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521