std::variant 在 MSVC 和 gcc

问题描述

MSVC 19.28 拒绝以下代码,但 gcc 10.2 接受并输出 true false

#include <iostream>
#include <variant>

int main()
{
    std::variant<long long,double> v{ 0 };
    std::cout << std::boolalpha << std::holds_alternative<long long>(v) << ' ' << std::holds_alternative<double>(v) << std::endl;
}

根据cppreference

  1. 转换构造函数。构造一个包含 由重载解析选择的替代类型 T_j 表达式 F(std::forward<T>(t)) 如果有重载 作用域内 F(T_i) 中的每个 T_i 的虚函数 Types... 同时,除了: 仅在以下情况下才考虑重载 F(T_i) 声明 T_i x[] = { std::forward<T>(t) }; 对某些人有效 发明变量x; 直接初始化包含的值,就像通过来自 std::forward<T>(t) 的直接非列表初始化一样。

并且问题通过重载解析转换为F(long long)F(double)的哪个函数被选择为反对参数1

int 转换为 long long 是一个整数转换(假设 sizeof(long long) 大于 sizeof(int))并且将 int 转换为 double 是一个整数转换浮动整数转换,两者的排名都不高于另一个。所以调用不明确,程序格式错误。

MSVC 确实如我所料拒绝了该代码,但令我惊讶的是,gcc 接受了它。另外,在cppreference上也有类似的例子:

std::variant<std::string> v("abc"); // OK
std::variant<std::string,std::string> w("abc"); // ill-formed
std::variant<std::string,const char*> x("abc"); // OK,chooses const char*
std::variant<std::string,bool> y("abc"); // OK,chooses string; bool is not a candidate
/* THIS ONE -> */ std::variant<float,long,double> z = 0; // OK,holds long
                                         // float and double are not candidates 

所以我的问题是:是 gcc 还是 MSVC 不符合,还是我的理解有误?

解决方法

在引用的规则中,只有当候选类型的copy-list-initialization从参数类型工作时才考虑重载。此检查不(不能)考虑参数的常量表达式状态,因此 int 到任何浮点类型是缩小 转换,列表初始化不允许(尽管在典型的实现中,double 可以准确地表示 int 的每个值)。因此,GCC(、libstdc++)对于忽略 double 替代方案是正确的

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...