When looking at std::visit() page in cppreference,
https://en.cppreference.com/w/cpp/utility/variant/visit, I encountered the code I can't make sense of...
Here's the abbreviated version:
#include <iomanip>
#include <iostream>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
int main() {
std::vector<std::variant<int,long,double,std::string>> vec = { 10, 15l, 1.5, "hello" };
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);
}
}
What do the two lines declaring overloaded, just above int main(), mean?
Thank you for explaining!
2019 Addition
After the two gentlemen below provided detailed explanations (thank you so much!), I've stumbled upon the same code in the very fine book C++17 in Detail -
Learn the Exciting Features of The New C++ Standard! by Bartłomiej Filipek. Such a well written book!
The first one
is a classic class/struct declaration/definition/implementation. Valid from C++11 (because use variadic templates).
In this case,
overloadedinherits from all template parameters and enables (usingrow) all inheritedoperator(). This is an example of Variadic CRTP.Unfortunately the variadic
usingis available only starting from C++17.The second one
is a "deduction guide" (see this page for more details) and it's a new C++17 feature.
In your case, the deduction guide says that when you write something as
or also
ovbecomes anoverloaded<decltype(arg1), decltype(arg2), decltype(arg3), decltype(arg4)>This permits you to write something as
that in C++14 was
-- EDIT --
As pointed by Nemo (thanks!) in the example code in your question there is another interesting new C++17 feature: the aggregate initialization of base classes.
I mean... when you write
you're passing three lambda functions to initialize three base classes of
overloaded.Before C++17, you could do this only if you wrote an explicit constructor to do it. Starting from C++17, it works automatically.
At this point, it seems to me that it can be useful to show a simplified full example of your
overloadedin C++17 and a corresponding C++14 example.I propose the following C++17 program
and the best C++14 alternative (following also the bolov's suggestion of a "make" function and his recursive
overloadedexample) that I can imagine.I suppose that it's matter of opinion, but it seems to me that the C++17 version is a lot simpler and more elegant.