为什么在GCC 8.5和GCC 12.1上,std::variant在处理const char *字面值时表现不同?

3
#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

为什么输出结果不同?根据c++17标准哪个是正确的?我应该怎样修改代码以使它在两个版本的GCC上执行结果一致?

https://dev59.com/-lEG5IYBdhLWcg3weOkT - user7610
5
看起来LWG3228是C++17中的一个缺陷,被P1957R2修复。我猜测GCC 8.5.0没有将此修复移植回去。 - Yksisarvinen
是的,那是一个特别恶劣的语言缺陷,导致了完全不直观的行为。 - Paul Sanders
2个回答

1
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; }
};

存储其中之一(而不是bool)。

它只接受实际的bool和其他explicit_bool作为参数。

在这样做之后,您可能需要在代码中添加一些显式的bool转换。有趣的是,与许多其他C风格的转换相比较C++风格的转换,(bool)作为转换始终执行与static_cast<bool>完全相同的操作,这可以使它变得不那么痛苦。另一个选择是!!,它可以隐式地将大多数类型转换为bool


0
为了解决GCC 8.5的问题,我正在更改变量。
std::variant<std::string, const char *, bool> v{ "hasta la vista" };

这在 GCC 12 和 GCC 8 上都给了我一个 const char *。看起来 const char * 胜过 bool

在随后的代码中,我处理了提供字符串的两种方式。我认为这比保持变量不变并要求用户传递 std::string("hasta la vista") 或者处理 ""s 后缀魔法更好。任何一种方式都很容易被忘记,然后我就会陷入麻烦!

想不出更好的方法了。


请注意,原始指针不拥有它们的目标。在您的变量中持有的 const char* 可能会在您想要使用它之前失效。 - Drew Dormann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接