在继承自std :: variant的类上使用std :: visit - libstdc ++ vs libc ++

Vit*_*meo 19 c++ variant language-lawyer c++17

请考虑以下代码段:

struct v : std::variant<int, std::vector<v>> { };

int main()
{
    std::visit([](auto){ }, v{0});
}
Run Code Online (Sandbox Code Playgroud)
  • clang ++ 7用-stdlib=libc++ -std=c++2a编译代码;

  • g ++ 9 -std=c++2a无法编译代码,出现以下错误:

    /opt/compiler-explorer/gcc-trunk-20180711/include/c++/9.0.0/variant:94:29:错误:嵌套名称说明符中使用的不完整类型'std :: variant_size'

     inline constexpr size_t variant_size_v = variant_size<_Variant>::value;
    
                             ^~~~~~~~~~~~~~
    
    Run Code Online (Sandbox Code Playgroud)

godbolt.org上的实例


  • 两种实现都符合标准吗?

  • 如果没有,这里的实施是正确的,为什么?

T.C*_*.C. 13

C++ 17中的[variant.visit]不使用variant_size_v,但它在当前工作草案中作为编辑更改的结果.我没有看到任何迹象表明LWG在进入之前对其进行了审核,但是从那时起它已经多次查看过这部分标准并且还没有反对它,所以我假设它已经在事实要求.

与此同时,LWG问题3052(已提交给LEWG)明确要求std::variant.当问题得到解决时 - 不管怎样 - 它也应该解决这个问题.


Ser*_*eyA 9

看起来它是gcc实现中的一个错误.根据cppreference,它被称为呼吁invokea std::get.std::get<>是为可转换为的任何东西定义的std::variant(因为它std::variant通过转发引用接受参数).您的结构可以转换为std::variant,因此std::get它本身适用于您在gcc中的结构.

gcc实现选择使用a std::variant_size作为其实现的一部分visit的事实是它们的实现细节,并且它不(并且不应该)适用于您的struct的事实是无关紧要的.

结论:由于实施中的疏忽,这是gcc中的一个错误.

  • 引用cppreference"这是合法的"是值得怀疑的; 在标记为[语言 - 律师]的问题中,这是完全错误的.cppreference包含"如何使用"合理的信息; 对于实施怪癖,它包含"我们告诉孩子的谎言". (6认同)
  • @Yakk-AdamNevraumont,我同意,但我列出它是为了方便。C++ 17 标准在这方面没有什么不同,它实际上具有相同的措辞。 (2认同)