I am trying to understand the example provided at cppreference for std::visit
. Here is the example from that link:
#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
template<class T> struct always_false : std::false_type {};
using var_t = std::variant<int, long, double, std::string>;
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main() {
std::vector<var_t> vec = {10, 15l, 1.5, "hello"};
for(auto& v: vec) {
// void visitor, only called for side-effects
std::visit([](auto&& arg){std::cout << arg;}, v);
// value-returning visitor. A common idiom is to return another variant
var_t w = std::visit([](auto&& arg) -> var_t {return arg + arg;}, v);
std::cout << ". After doubling, variant holds ";
// type-matching visitor: can also be a class with 4 overloaded operator()'s
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, int>)
std::cout << "int with value " << arg << '\n';
else if constexpr (std::is_same_v<T, long>)
std::cout << "long with value " << arg << '\n';
else if constexpr (std::is_same_v<T, double>)
std::cout << "double with value " << arg << '\n';
else if constexpr (std::is_same_v<T, std::string>)
std::cout << "std::string with value " << std::quoted(arg) << '\n';
else
static_assert(always_false<T>::value, "non-exhaustive visitor!");
}, w);
}
for (auto& v: vec) {
std::visit(overloaded {
[](auto arg) { std::cout << arg << ' '; },
[](double arg) { std::cout << std::fixed << arg << ' '; },
[](const std::string& arg) { std::cout << std::quoted(arg) << ' '; },
}, v);
}
}
I am particularly interested in the overloaded
declarations:
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
The first of these makes sense - the struct overloaded
is being declared with constructors for each type it encapsulates. However I don't understand the purpose of the second. This seems to be a function declaration similar to:
template<class... Ts> overloaded<Ts...> overloaded(Ts...);
But the function is never defined, so how can it be used later in the example? If this is just a constructor then why doesn't it need an overloaded::
prefix and where is the body? I think I am just misunderstanding what the trailing return type declaration "expands" into so any insight into what is accomplished by the overloaded(Ts...)
declaration would be appreciated.