首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GNU::C++实现中的更改

GNU::C++实现中的更改
EN

Stack Overflow用户
提问于 2021-07-27 16:06:07
回答 2查看 149关注 0票数 0

我有以下关于std::variant用法的示例:

代码语言:javascript
复制
#include <iostream>
#include <string>
#include <variant>

class Cat {
public:
    const std::string& getSound() const { return sound; };

private:
    std::string sound = "Meow.";
};

class Dog {
public:
    const std::string& getSound() const { return sound; };

private:
    std::string sound = "Bark.";
};

class House {
public:
    void resetAnimal(const auto&& animal) { v = std::move(animal); }
    const auto& getAnimal() const {
        return std::visit([](const auto& animal) -> decltype(animal)&
                          { return animal; }, v);
    }

private:
    std::variant<Cat, Dog> v;
};

int main() {
    House house;
    house.resetAnimal(Cat());

    std::cout << house.getAnimal().getSound() << std::endl;

    house.resetAnimal(Dog());

    std::cout << house.getAnimal().getSound() << std::endl;
    
    return 0;
}

有趣的是,它用压缩器编译,从g++-8到g++-10。(使用标志-std=c++17-fpermissive),并在使用g++-11时失败。如果它编译,它就会像预期的那样工作--打印“Meow.‘”。还有“巴克”在不同的线路上。错误信息看起来如下(g++-11):

代码语言:javascript
复制
In file included from <source>:3:
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/variant: In instantiation of 'constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = House::getAnimal() const::<lambda(const auto:23&)>; _Variants = {const std::variant<Cat, Dog>&}]':
<source>:25:26:   required from here
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/variant:1758:29: error: static assertion failed: std::visit requires the visitor to have the same return type for all alternatives of a variant
 1758 |               static_assert(__visit_rettypes_match,
      |                             ^~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-11.1.0/include/c++/11.1.0/variant:1758:29: note: '__visit_rettypes_match' evaluates to false
<source>: In member function 'const auto& House::getAnimal() const':
<source>:26:48: error: forming reference to void
   26 |                           { return animal; }, v);
      |                                                ^
Compiler returned: 1

在使用MSVC进行填充时,我得到了含义非常接近的消息。我的问题是:

  • 是否可以使用g++-11编译示例代码?如果答案是“是”,那怎么回答?
  • 为什么添加-fpermissive使g++压缩器在这种情况下工作呢?
  • 是否可以使用MSVC编译示例代码?
  • 是否可以使用clang进行编译?(我试过了)

我知道继承和模板。我只是有兴趣,有没有可能像我在这个例子中做的那样。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-07-27 16:28:37

gcc-8允许这样做是错误的,当您尝试使用它时会产生坏代码。

暂且不谈std::visit()std::variant<>的官方定义,从纯语言的角度来看,这是直觉上的情况。

为了演示这一点,让我们问自己一个问题:“getAnimal()的返回类型是什么?”毕竟,这必须在编译时确定。

返回auto的函数的返回类型完全由其参数决定。在这种情况下,只有House this,而没有其他任何东西。因此,变体的当前状态不能影响返回的类型。可能是什么?也许是某种推断的受抚养人variant<>?但是这样就不能直接调用getSound()了,所以不可能是它。

让我们不要再想了,我们可以用typeid()自己检查一下

代码语言:javascript
复制
using T = decltype(std::declval<House>().getAnimal());
std::cout << typeid(T).name() << "\n";

// ...
result:
  3Cat

看来我们只会把猫从这个功能中救出来!我们可以通过稍微修改代码来确认这一点:

代码语言:javascript
复制
class Cat {
public:
    const std::string& getSound() const { 
      std::cout << "I am cat\n"; 
      return sound; 
    };

private:
    std::string sound = "Meow.";
};

class Dog {
public:
    const std::string& getSound() const { 
      std::cout << "I am dog\n"; 
      return sound; 
    };

private:
    std::string sound = "Bark.";
};

//...
result:
  I am cat
  Meow.
  I am cat    <--------- !!!!!!
  Bark.

在您的示例中,它“工作”这一事实是一个小奇迹,因为CatDog恰好具有等效的内存布局。

它仍然是未定义的行为,即使它“有效”。

票数 3
EN

Stack Overflow用户

发布于 2021-07-27 16:28:31

对于科技促进发展:访问,访问者是一个可调用的函数,它可以从变体返回相同类型的R。您的访客返回不同类型。GCC的libstdc++直到GCC11才检查这条规则。这是更新后,诊断添加了:libstdc++:修正访问者返回类型诊断[PR97449]

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68548299

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档