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

时间:2018-07-12 15:28:12

标签: c++ language-lawyer c++17 variant

请考虑以下代码段:

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

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

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

      

    / 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;
    
                             ^~~~~~~~~~~~~~
    

live example on godbolt.org


  • 两个实现均符合标准吗?

  • 如果不是,什么实现在这里正确,为什么?

3 个答案:

答案 0 :(得分:12)

[variant.visit] in C++17不使用variant_size_v,但由于current working draft而在editorial change中使用。我看不到任何迹象表明LWG在进行更改之前已经对其进行了审核,但是自那以后它已经对该标准的这一部分进行了多次考察,并且尚未反对它,因此我将假定它已经在需要事实。

与此同时,已被称为LEWG的LWG issue 3052将明确要求std::variant。解决该问题(一种方法或另一种方法)后,它也应解决此问题。

答案 1 :(得分:8)

看起来这是gcc实现中的错误。根据{{​​3}},它的调用就像在invoke上调用std::get一样。 std::get<>定义为可转换为std::variant的任何内容(因为它通过转发引用接受std::variant自变量)。您的结构可以转换为std::variant,因此std::get本身可以在gcc中对您的结构起作用。

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

结论:由于实施过程中的疏忽,这是gcc中的错误。

答案 2 :(得分:1)

最近我也遇到了这个问题。我想出了一种解决方法,该方法基本上专门针对从变体继承的类专门设计了variant_size和variant_alternative。

link on godbolt

它不漂亮,并且将东西注入到std名称空间中。我还不是元编程专家(至今!),所以我一起砍掉了它。也许其他人可以对此进行改进?

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

#include <utility>
#include <type_traits>



using var = std::variant<int, bool, float, std::string>;

struct myvar : public var {
    using var::var;
    using var::operator=;

};

namespace std{

    template<>
    struct variant_size<myvar> : variant_size<var> {
    };

    template<std::size_t I>
    struct variant_alternative<I,myvar> :  variant_alternative<I,var> {
    };
}

int main(){

    constexpr int vs = std::variant_size<var>::value;

    myvar s = std::string{"boo!"}; 
    std::visit([](auto&& e){std::cout << e << "\n";}, s);
    std::cout << vs;
}