是否可以在没有 lambdas 的情况下使用 std::visit (只是一个简单的类)?

use*_*491 5 c++ visitor variant c++17

我正在尝试使用一个简单的类来创建访问者,并为变体中的每种类型重载 operator()。

我预计这会起作用(因为我认为它适用于 lamdba 函数):

#include <variant>
#include <iostream>

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

class ExampleVisitor {
  void operator()(int& i) {
    std::cout << "Integer: " << i << '\n';
  }

  void operator()(float& f) {
    std::cout << "Float: " << f << '\n';
  }

  void operator()(bool& b) {
    std::cout << "Boolean: " << b << '\n';
  }
};

int main() {
  Example example = 1234;
  ExampleVisitor visitor;
  std::visit(visitor, example);
}
Run Code Online (Sandbox Code Playgroud)

然而,编译这段代码(在 gcc 9.3.0 版上)会导致一个相当神秘的错误 error: no type named ‘type’,我真的无法理解。我认为这与std::visit推断访问者的返回类型有关,但我不太确定修复方法。

完整错误:

In file included from visit.cpp:1:
/usr/include/c++/9/variant: In instantiation of ‘constexpr decltype(auto) std::__do_visit(_Visitor&&, _Variants&& ...) [with bool __use_index = false; bool __same_return_types = true; _Visitor = ExampleVisitor&; _Variants = {std::variant<int, float, bool>&}]’:
/usr/include/c++/9/variant:1654:24:   required from ‘constexpr decltype(auto) std::visit(_Visitor&&, _Variants&& ...) [with _Visitor = ExampleVisitor&; _Variants = {std::variant<int, float, bool>&}]’
visit.cpp:23:30:   required from here
/usr/include/c++/9/variant:1634:13: error: no type named ‘type’ in ‘std::conditional_t<false, std::__detail::__variant::__variant_idx_cookie, std::invoke_result<ExampleVisitor&, int&> >’ {aka ‘struct std::invoke_result<ExampleVisitor&, int&>’}
 1634 |       using _Result_type = typename std::conditional_t<__use_index,
      |             ^~~~~~~~~~~~
/usr/include/c++/9/variant:1638:23: error: no type named ‘type’ in ‘std::conditional<false, std::__detail::__variant::__variant_idx_cookie, std::invoke_result<ExampleVisitor&, int&> >::type’ {aka ‘struct std::invoke_result<ExampleVisitor&, int&>’}
 1638 |       constexpr auto& __vtable = __detail::__variant::__gen_vtable<
      |  
Run Code Online (Sandbox Code Playgroud)

cig*_*ien 13

是的,这当然是可能的。问题是,你在里面设置的重载ExampleVisitorprivate,所以std::visit没有找到合适operator()的使用(据它所知,根本不operator()存在 s )。

您可以通过设置重载来解决此问题public

class ExampleVisitor {
    public:
  //  ...  all overloads
};
Run Code Online (Sandbox Code Playgroud)

或者通过将更改默认访问说明符的classinto a struct

这是一个演示