Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use std::visit without lambdas (just a simple class)? [closed]

I'm trying to experiment with making a visitor with just a simple class, with overloads of operator() for each type in the variant.

I expected this to work (as it's how I assumed it worked for lamdba functions):

#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);
}

However compiling this code (on gcc version 9.3.0) results in a rather cryptic error error: no type named ‘type’, which I can't really understand. I think it has something to do with std::visit deducing the return type of the visitor, but I'm not too sure on the fix.

Full error:

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<
      |  
like image 657
user3818491 Avatar asked Oct 06 '20 13:10

user3818491


1 Answers

Yes, it's certainly possible. The issue is, your overload set inside ExampleVisitor is private, so std::visit doesn't find an appropriate operator() to use (as far as it can tell, no operator()s exist at all).

You can fix this by just making the overload set public:

class ExampleVisitor {
    public:
  //  ...  all overloads
};

Or by making the class into a struct which changes the default access specifier.

Here's a demo.

like image 113
cigien Avatar answered Oct 26 '22 07:10

cigien