当前位置: 首页 > 知识库问答 >
问题:

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

邓阳嘉
2023-03-14

考虑以下代码片段:

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

int main()
{
    std::visit([](auto){ }, v{0});
}

>

带有-std=C2A的G9未能编译代码,错误如下:

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

                         ^~~~~~~~~~~~~~

godbolt上的活生生的例子。组织

>

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

共有3个答案

邓元白
2023-03-14

我最近也遇到了这个问题。我想出了一个解决方法,基本上专门为继承自变体的类variant_size和variant_alternative...

拉杆

它不漂亮,它会向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;
}

农飞翔
2023-03-14

看起来这是gcc实现中的一个错误。根据cp首选项,它的调用就好像在std::get上调调用一样。std::get

gcc实现选择使用std::variant_size作为其访问实现的一部分这一事实是它们的实现细节,它不(也不应该)为你的结构工作这一事实是无关紧要的。

结论:这是gcc中的一个缺陷,因为在实施过程中存在疏忽。

海典
2023-03-14

C 17中的[variant.visit]没有使用variant_size_v,但由于编辑上的更改,它在当前的工作草案中使用。我看不到任何迹象表明LWG在引入之前审查了变更,但自那以后,它已经多次查看了标准的这一部分,并且还没有提出反对意见,所以我将假设它实际上是必需的。

同时,LWG第3052版(已被提交给LEWG)将明确要求std::variant。当这个问题得到解决时——不管怎样——它也应该解决这个问题。

 类似资料:
  • 在我的Fedora 34环境(g)中,定义为: 如果表达式已经是右值,那么

  • 我在理解条件变量及其在互斥体中的使用时遇到了一些困难,我希望社区能帮助我。请注意,我来自win32背景,因此与CRITICAL_SECTION、HANDLE、SetEvent、WaitForMultipleObject等一起使用。 这是我第一次尝试使用C++11标准库进行并发操作,它是在这里找到的一个程序示例的修改版本。 关于这个的几个问题。 我读过“任何要等待std::condition_var

  • 当索引仅在运行时已知时,从所需类型的索引默认构造std::variant的最简单方法是什么?换句话说,我想写: 请注意,不能设置为constexpr,因此在这里不起作用。 当然,这里的问题是,由于不知道在编译时要调用中的哪个构造函数,所以基本上必须在编译时生成一个包含所有可能的构造函数(或者可能是要从中复制的默认构造变量)的表,然后在运行时访问该表。这里显然有一些模板魔法,但是什么是最干净的方法呢

  • 错误:无法将类型为“std::_bit_reference&”的非常量lvalue引用绑定到类型为“std::vector::reference”{aka“std::_bit_reference”}的rvalue 因此,它抱怨,因为只有第二个参数是rvalue

  • 我会期望std::reference_wrapper在将non-const转换为const方面可以作为参考,例如: 下面的代码在MSVC和GCC中编译并运行良好,但在Clang上则不行。我只是不明白为什么,它是UB,还是实际上是关于Clang编译器的问题? 仅在Clang上,显示以下错误: https://wandbox.org/permlink/FSY4tCvE9B17hbVn

  • 在下面的代码中,我展示了类似联合的类S,它包含两个不相关的结构B和C。我展示了如何实例化非POD std::字符串并再次删除它,然后将S切换到S::CC 并设置num int。 然而,我的目标是在std::initializer\u列表中使用S。我不知道初始化h的格式应该是什么。如果我想用这些S::BB,S::CC,S::BB初始化h,参数应该是什么? 我的编译器是VS2015。 编辑:这篇文章的