Search code examples
c++gccc++17std-variant

Why does std::variant behave differently on GCC 8.5 and GCC 12.1 in respect to a `const char *` literal?


#include <iostream>
#include <string>
#include <variant>

int main()
{
    std::variant<std::string, bool> v{ "hasta la vista" };
    std::cout << std::boolalpha << std::holds_alternative<std::string>(v) << ' ' << std::holds_alternative<bool>(v) << std::endl;
}

GCC 12.1.1

$ g++ std_alternative.cpp 
$ ./a.out 
true false

GCC 8.5.0

$ g++ -std=c++17 std_alternative.cpp 
$ ./a.out 
false true

Why is the output different? Which is correct according to c++17? What should I do so that my code works on both versions of GCC the same way?


Solution

  • struct explicit_bool {
      bool b = false;
      template<class T,
       std::enable_if_t<std::is_same_v<T, bool>, bool> = true
      >
      explicit_bool( T v ):b(v){}
      explicit_bool(explicit_bool const&) noexcept=default;
      explicit_bool& operator=(explicit_bool const&)& noexcept=default;
      explicit_bool()noexcept=default;
      ~explicit_bool()noexcept=default;
      bool operator!() const { return !b; }
      explicit operator bool() const { return b; }
    };
    

    store one of these (instead of a bool).

    It only accepts actual bools and other explicit_bools as arguments.

    You may have to add some explicit casts to-from bool in your code after doing this. It may be of interest to you that (bool) as a cast always does the exact same thing as static_cast<bool> does, unlike many other C-style casts compared to C++ style casts; this can make it less painful. Another choice is !!, which converts most types to bool implicitly.