3

我有下面的代码,为什么visitor1visitor2给出错误?这是否意味着访问者不能在变体中返回一种类型?

#include <iostream>
#include <variant>


struct Visitor1
{
    template <class T>
    T operator()(const T & t) const
    {
        return (t);
    }
};

struct Visitor2
{
    int operator()(const int  & t) const
    {
        return std::get<int>(t);
    }

    char operator()(const char & t) const
    {
        return std::get<char>(t);
    }
};

struct Visitor3
{
    void operator()(const int & t) const
    {
        std::cout<<t;
    }
    void operator()(const char & t) const
    {
        std::cout<<t;
    }
};

int main()
{
    std::variant<int, char> v{char(100)};

    std::visit(Visitor3{}, v);

    auto t = std::visit(Visitor2{}, v);  //fails
    //auto t = std::visit(Visitor1{}, v); //fails
    std::cout << t;
}

我知道我可以使用std::get(),但问题是我只能使用autowith std::get(),如果我执行以下操作,x则在 if/else 范围之外无法访问:

bool b;
Variant v;
if (b)
{
   auto x = std::get<int>(v);
}
else
{
   auto x = std::get<char>(v);
}
// I want to do something with x here out of if/else
4

3 回答 3

3

一种语言可能存在具有 C++ 的许多功能来满足您的需求。

为了做你想做的事,当你调用时std::visit,必须编写函数其余部分的 N 个不同实现。

在这 N 个不同的实现中的每一个(在您的情况下为 2 个)中,变量的类型都会不同。

C++ 不是这样工作的。

访问调用“乘以”的唯一部分代码是访问者。

int main()
{
  std::variant<int, char> v{char(100)};

  std::visit([&](auto && t){
    std::cout << t;
  }, v);
}

我将函数主体的其余部分放在访问者中。对于可以存储在访问者中的每种类型,该代码都会实例化一次。

从访问返回的任何内容都会返回到调用范围的“单个实例”主体。

基本上,[&](auto&& t)lambdas 做你想做的事。


现在,我们可以做一些技巧来稍微改变语法。

我最喜欢的是:

v->*visit*[&](auto&& val) {
  std::cout << val;
  return [val](auto&& x) { x << val; };
}->*visit*[&](auto&& outputter) {
  outputer(std::cout);
};

where->*visit*使用相对荒谬的元编程来允许

  1. 指定运营商引起访问,

  2. 将访问的返回值融合到一个变体中。

但是没有一个理智的人会写那个代码。

于 2018-11-05T18:25:27.000 回答
1

我有下面的代码,为什么 visitor1 和 visitor2 会出错?

因为 C++ 是一种强类型语言。

当你写

auto t = std::visit(Visitor2{}, v);  //fails

编译器必须在编译时决定哪种类型是t,所以必须决定哪种类型返回std::visit(Visitor2{}, v)

如果Visitor2return a char, when vcontains a char, or a int, when contains va ,int编译器无法选择(编译时!)从std::visit()[返回的类型还有一个问题(Visitor2仅)t,在operator()'s 内部是 aint或 a char,所以你不能申请std::get()]。

同样的问题Visitor1:模板operator()返回模板类型 sointcharfor a std::variant<int, char>

Visitor3之所以有效,是因为两者都operator()return void,因此编译器可以解析(编译时)std::visit(Visitor3{}, v)返回(在某种意义上)void

也许在此页面中得到更好的解释:

[ std::visit()] 有效返回

std::invoke(std::forward<Visitor>(vis), std::get<is>(std::forward<Variants>(vars))...) 

,在is...哪里vars.index()...。返回类型是从返回的表达式推导出来的,就像 by 一样decltype

对于所有变体的替代类型的所有组合,如果上述调用不是相同类型和值类别的有效表达式,则调用格式错误

于 2018-11-05T18:00:04.063 回答
1

你可以做

bool b;
Variant v;
std_optional<char> x_char;
std_optional<int> x_int;
if (b)
{
   x_int = std::get<int>(v);
}
else
{
   x_char = std::get<char>(v);
}
于 2018-11-05T18:30:49.917 回答