Seek to understand std::visit better [closed]
Asked Answered
R

2

6

From https://en.cppreference.com/w/cpp/utility/variant/visit :

  1. what's the return value of visit? I don't understand "selected invocation of visitor"?

The sample code

// Don't understand what this means, can explain? It's a templated func with trailing return type but no body?
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

// Why would the visitor function use && instead of &?
std::visit([](auto&& arg){std::cout << arg;}, v);
Robertoroberts answered 25/1, 2020 at 1:30 Comment(1)
put this code into cppinsights.io This will expand the variadic templates and you will see immediately what is going on. Note that template<class... Ts> overloaded(Ts...) -> overloaded<Ts...> is a deduction guide.Simarouba
A
7

The easiest way to understand visitors is by comparing them to polymorphism. In polymorphic classes, you have a base class, which has virtual functions, and derived classes, which override these functions. You create objects of the derived classes, and store them as if they are objects of the base class (as pointers, mostly). When you call the virtual functions in the base class pointers, they will call the functions from the type that you originally created, which is the derived classes types.

Visitors are exactly the same, but are type-safe. However, visitors don't have a base type. You basically store all the "derived" types, i.e., the types that have the methods to be called, in a variant object (they're not really stored, they're really mutually exclusive, which is in the nature of variant). A variant is agnostic to the type of object it holds, just like the base class is agnostic to the derived type it holds. And just like calling a method in the base class pointer (mentioned above), will result in the overriding method to be called in the derived, the same applies to variants. When you "visit", the correct variant of the class will be used to call the function underneath.

Here's the catch: When you put multiple types in a variant, and you visit the methods in them, unlike the polymorphic type structures, methods don't have to share the same return type. So if a method in a class returns int, and the other method with the same name in another class returns a double, and you visit a variant that contains both, depending on which is instantiated in the variant, the correct return type will be returned.

Too much text, I know. Hope that helps.

Affined answered 25/1, 2020 at 10:7 Comment(0)
H
2

From the documentation the std::visit return what the visitor return.

The value returned by the selected invocation of the visitor.

Using a visitor that return void like [](auto&& arg){std::cout << arg;}, std::visit will return void

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

Using a visitor that return var_t like [](auto&& arg) -> var_t {return arg + arg;}, std::visit will return var_t

var_t w = std::visit([](auto&& arg) -> var_t {return arg + arg;}, v);

The overloaded is to create the visitor wrapping with :

template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

Then you can create the visitor with

auto visitor = overloaded {
        [](auto arg) { std::cout << arg << ' '; },
        [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
    };

Next it could be called with :

std::visit(visitor, v);

In this case the visitor return void then std::visit also return void

Heterogenesis answered 25/1, 2020 at 9:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.