Confusing templates in C++17 example of std::visit
Clash Royale CLAN TAG#URR8PPP
up vote
6
down vote
favorite
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>
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)
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 are the two lines declaring overloaded
, just above int main()
, mean?
Thank you for explaining!
c++ templates c++17 variadic-templates
add a comment |Â
up vote
6
down vote
favorite
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>
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)
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 are the two lines declaring overloaded
, just above int main()
, mean?
Thank you for explaining!
c++ templates c++17 variadic-templates
Anybody can shine some light on the initialization here? Why doesn'toverloads(/* some lambdas */);
work, butoverloads/* some lambdas */;
does? Notice the uniform initialization vs parentheses initialization.
â Fureeish
22 mins ago
add a comment |Â
up vote
6
down vote
favorite
up vote
6
down vote
favorite
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>
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)
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 are the two lines declaring overloaded
, just above int main()
, mean?
Thank you for explaining!
c++ templates c++17 variadic-templates
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>
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)
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 are the two lines declaring overloaded
, just above int main()
, mean?
Thank you for explaining!
c++ templates c++17 variadic-templates
c++ templates c++17 variadic-templates
edited 54 mins ago
max66
29.7k63156
29.7k63156
asked 1 hour ago
Boris
8818
8818
Anybody can shine some light on the initialization here? Why doesn'toverloads(/* some lambdas */);
work, butoverloads/* some lambdas */;
does? Notice the uniform initialization vs parentheses initialization.
â Fureeish
22 mins ago
add a comment |Â
Anybody can shine some light on the initialization here? Why doesn'toverloads(/* some lambdas */);
work, butoverloads/* some lambdas */;
does? Notice the uniform initialization vs parentheses initialization.
â Fureeish
22 mins ago
Anybody can shine some light on the initialization here? Why doesn't
overloads(/* some lambdas */);
work, but overloads/* some lambdas */;
does? Notice the uniform initialization vs parentheses initialization.â Fureeish
22 mins ago
Anybody can shine some light on the initialization here? Why doesn't
overloads(/* some lambdas */);
work, but overloads/* some lambdas */;
does? Notice the uniform initialization vs parentheses initialization.â Fureeish
22 mins ago
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
6
down vote
accepted
Ahh, I love this.
It's a way to concisely declare a struct with a call operator overloaded on the set of the template arguments call operators.
template<class... Ts> struct overloaded : Ts... using Ts::operator()...; ;
overloaded
inherits from Ts...
and uses all of their operator()
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
This is a deduction guide so you don't specify the template parameters
The usage is as you see in the example.
It's a nice utility to create an overloaded set of multiple lambdas (and other function types).
Previous to C++17 you would have to use recursion to create overload
. Not pretty:
template <class... Fs> struct Overload : Fs...
;
template <class Head, class... Tail>
struct Overload<Head, Tail...> : Head, Overload<Tail...>
Overload(Head head, Tail... tail)
: Headhead, Overload<Tail...>tail...
using Head::operator();
using Overload<Tail...>::operator();
;
template <class F> struct Overload<F> : F
Overload(F f) : Ff
using F::operator();
;
template <class... Fs> auto make_overload_set(Fs... fs)
return Overload<Fs...>fs...;
auto test()
auto o = make_overload_set(
(int) return 24; ,
(char) return 11; );
o(2); // returns 24
o('a'); // return 11
The main nuisance is that Overload
because inherits is not an aggregate, so you need to do the recursion trick to create a constructor with all the types. In C++17 overloaded
is an aggregate (yey) so constructing one works out of the box :). You also need to specify using::operator()
for each of them.
You missed the worst part!using Head::operator(); using Overload<Tail..>::operator();
â Barry
44 mins ago
@Barry clang compiles it withoutusing
, so I just assumed it's something about inheriting one by one that makes that possible. After your comment I double checked andgcc
complains about ambiguity, so maybe it's a clang "feature". Will correct in answer.
â bolov
26 mins ago
Yeah, alternatively a clang bug :-)
â Barry
22 mins ago
add a comment |Â
up vote
5
down vote
What are the two lines declaring overloaded, just above int main(), mean?
The first one
template<class... Ts>
struct overloaded : Ts...
using Ts::operator()...; ;
is a classic class/struct declaration/definition/implementation. Valid from C++11 (because use variadic templates).
In this case, overload
inherit from all template parameters and enable (using
row) all inherited operator()
.
Unfortunately the variadic using
is available only starting from C++17.
The second one
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
is a "deduction guide" (see this page for more details) and it's a new C++17 feature.
In your case, the deduction guide say that when you write something as
auto ov = overloaded arg1, arg2, arg3, arg4 ;
or also
overloaded ov arg1, args, arg3, arg4 ;
ov
become a overloaded<decltype(arg1), decltype(arg2), decltype(arg3), decltype(arg4)>
This permit you to write something as
overloaded
(auto arg) std::cout << arg << ' '; ,
(double arg) std::cout << std::fixed << arg << ' '; ,
(const std::string& arg) std::cout << std::quoted(arg) << ' '; ,
that in C++14 was
auto l1 = (auto arg) std::cout << arg << ' '; ;
auto l2 = (double arg) std::cout << std::fixed << arg << ' '; ;
auto l3 = (const std::string& arg) std::cout << std::quoted(arg) << ' ';
overloaded<decltype(l1), decltype(l2), decltype(l3)> ovl1, l2, l3;
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
accepted
Ahh, I love this.
It's a way to concisely declare a struct with a call operator overloaded on the set of the template arguments call operators.
template<class... Ts> struct overloaded : Ts... using Ts::operator()...; ;
overloaded
inherits from Ts...
and uses all of their operator()
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
This is a deduction guide so you don't specify the template parameters
The usage is as you see in the example.
It's a nice utility to create an overloaded set of multiple lambdas (and other function types).
Previous to C++17 you would have to use recursion to create overload
. Not pretty:
template <class... Fs> struct Overload : Fs...
;
template <class Head, class... Tail>
struct Overload<Head, Tail...> : Head, Overload<Tail...>
Overload(Head head, Tail... tail)
: Headhead, Overload<Tail...>tail...
using Head::operator();
using Overload<Tail...>::operator();
;
template <class F> struct Overload<F> : F
Overload(F f) : Ff
using F::operator();
;
template <class... Fs> auto make_overload_set(Fs... fs)
return Overload<Fs...>fs...;
auto test()
auto o = make_overload_set(
(int) return 24; ,
(char) return 11; );
o(2); // returns 24
o('a'); // return 11
The main nuisance is that Overload
because inherits is not an aggregate, so you need to do the recursion trick to create a constructor with all the types. In C++17 overloaded
is an aggregate (yey) so constructing one works out of the box :). You also need to specify using::operator()
for each of them.
You missed the worst part!using Head::operator(); using Overload<Tail..>::operator();
â Barry
44 mins ago
@Barry clang compiles it withoutusing
, so I just assumed it's something about inheriting one by one that makes that possible. After your comment I double checked andgcc
complains about ambiguity, so maybe it's a clang "feature". Will correct in answer.
â bolov
26 mins ago
Yeah, alternatively a clang bug :-)
â Barry
22 mins ago
add a comment |Â
up vote
6
down vote
accepted
Ahh, I love this.
It's a way to concisely declare a struct with a call operator overloaded on the set of the template arguments call operators.
template<class... Ts> struct overloaded : Ts... using Ts::operator()...; ;
overloaded
inherits from Ts...
and uses all of their operator()
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
This is a deduction guide so you don't specify the template parameters
The usage is as you see in the example.
It's a nice utility to create an overloaded set of multiple lambdas (and other function types).
Previous to C++17 you would have to use recursion to create overload
. Not pretty:
template <class... Fs> struct Overload : Fs...
;
template <class Head, class... Tail>
struct Overload<Head, Tail...> : Head, Overload<Tail...>
Overload(Head head, Tail... tail)
: Headhead, Overload<Tail...>tail...
using Head::operator();
using Overload<Tail...>::operator();
;
template <class F> struct Overload<F> : F
Overload(F f) : Ff
using F::operator();
;
template <class... Fs> auto make_overload_set(Fs... fs)
return Overload<Fs...>fs...;
auto test()
auto o = make_overload_set(
(int) return 24; ,
(char) return 11; );
o(2); // returns 24
o('a'); // return 11
The main nuisance is that Overload
because inherits is not an aggregate, so you need to do the recursion trick to create a constructor with all the types. In C++17 overloaded
is an aggregate (yey) so constructing one works out of the box :). You also need to specify using::operator()
for each of them.
You missed the worst part!using Head::operator(); using Overload<Tail..>::operator();
â Barry
44 mins ago
@Barry clang compiles it withoutusing
, so I just assumed it's something about inheriting one by one that makes that possible. After your comment I double checked andgcc
complains about ambiguity, so maybe it's a clang "feature". Will correct in answer.
â bolov
26 mins ago
Yeah, alternatively a clang bug :-)
â Barry
22 mins ago
add a comment |Â
up vote
6
down vote
accepted
up vote
6
down vote
accepted
Ahh, I love this.
It's a way to concisely declare a struct with a call operator overloaded on the set of the template arguments call operators.
template<class... Ts> struct overloaded : Ts... using Ts::operator()...; ;
overloaded
inherits from Ts...
and uses all of their operator()
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
This is a deduction guide so you don't specify the template parameters
The usage is as you see in the example.
It's a nice utility to create an overloaded set of multiple lambdas (and other function types).
Previous to C++17 you would have to use recursion to create overload
. Not pretty:
template <class... Fs> struct Overload : Fs...
;
template <class Head, class... Tail>
struct Overload<Head, Tail...> : Head, Overload<Tail...>
Overload(Head head, Tail... tail)
: Headhead, Overload<Tail...>tail...
using Head::operator();
using Overload<Tail...>::operator();
;
template <class F> struct Overload<F> : F
Overload(F f) : Ff
using F::operator();
;
template <class... Fs> auto make_overload_set(Fs... fs)
return Overload<Fs...>fs...;
auto test()
auto o = make_overload_set(
(int) return 24; ,
(char) return 11; );
o(2); // returns 24
o('a'); // return 11
The main nuisance is that Overload
because inherits is not an aggregate, so you need to do the recursion trick to create a constructor with all the types. In C++17 overloaded
is an aggregate (yey) so constructing one works out of the box :). You also need to specify using::operator()
for each of them.
Ahh, I love this.
It's a way to concisely declare a struct with a call operator overloaded on the set of the template arguments call operators.
template<class... Ts> struct overloaded : Ts... using Ts::operator()...; ;
overloaded
inherits from Ts...
and uses all of their operator()
template<class... Ts> overloaded(Ts...)->overloaded<Ts...>;
This is a deduction guide so you don't specify the template parameters
The usage is as you see in the example.
It's a nice utility to create an overloaded set of multiple lambdas (and other function types).
Previous to C++17 you would have to use recursion to create overload
. Not pretty:
template <class... Fs> struct Overload : Fs...
;
template <class Head, class... Tail>
struct Overload<Head, Tail...> : Head, Overload<Tail...>
Overload(Head head, Tail... tail)
: Headhead, Overload<Tail...>tail...
using Head::operator();
using Overload<Tail...>::operator();
;
template <class F> struct Overload<F> : F
Overload(F f) : Ff
using F::operator();
;
template <class... Fs> auto make_overload_set(Fs... fs)
return Overload<Fs...>fs...;
auto test()
auto o = make_overload_set(
(int) return 24; ,
(char) return 11; );
o(2); // returns 24
o('a'); // return 11
The main nuisance is that Overload
because inherits is not an aggregate, so you need to do the recursion trick to create a constructor with all the types. In C++17 overloaded
is an aggregate (yey) so constructing one works out of the box :). You also need to specify using::operator()
for each of them.
edited 23 mins ago
answered 1 hour ago
bolov
27.7k663119
27.7k663119
You missed the worst part!using Head::operator(); using Overload<Tail..>::operator();
â Barry
44 mins ago
@Barry clang compiles it withoutusing
, so I just assumed it's something about inheriting one by one that makes that possible. After your comment I double checked andgcc
complains about ambiguity, so maybe it's a clang "feature". Will correct in answer.
â bolov
26 mins ago
Yeah, alternatively a clang bug :-)
â Barry
22 mins ago
add a comment |Â
You missed the worst part!using Head::operator(); using Overload<Tail..>::operator();
â Barry
44 mins ago
@Barry clang compiles it withoutusing
, so I just assumed it's something about inheriting one by one that makes that possible. After your comment I double checked andgcc
complains about ambiguity, so maybe it's a clang "feature". Will correct in answer.
â bolov
26 mins ago
Yeah, alternatively a clang bug :-)
â Barry
22 mins ago
You missed the worst part!
using Head::operator(); using Overload<Tail..>::operator();
â Barry
44 mins ago
You missed the worst part!
using Head::operator(); using Overload<Tail..>::operator();
â Barry
44 mins ago
@Barry clang compiles it without
using
, so I just assumed it's something about inheriting one by one that makes that possible. After your comment I double checked and gcc
complains about ambiguity, so maybe it's a clang "feature". Will correct in answer.â bolov
26 mins ago
@Barry clang compiles it without
using
, so I just assumed it's something about inheriting one by one that makes that possible. After your comment I double checked and gcc
complains about ambiguity, so maybe it's a clang "feature". Will correct in answer.â bolov
26 mins ago
Yeah, alternatively a clang bug :-)
â Barry
22 mins ago
Yeah, alternatively a clang bug :-)
â Barry
22 mins ago
add a comment |Â
up vote
5
down vote
What are the two lines declaring overloaded, just above int main(), mean?
The first one
template<class... Ts>
struct overloaded : Ts...
using Ts::operator()...; ;
is a classic class/struct declaration/definition/implementation. Valid from C++11 (because use variadic templates).
In this case, overload
inherit from all template parameters and enable (using
row) all inherited operator()
.
Unfortunately the variadic using
is available only starting from C++17.
The second one
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
is a "deduction guide" (see this page for more details) and it's a new C++17 feature.
In your case, the deduction guide say that when you write something as
auto ov = overloaded arg1, arg2, arg3, arg4 ;
or also
overloaded ov arg1, args, arg3, arg4 ;
ov
become a overloaded<decltype(arg1), decltype(arg2), decltype(arg3), decltype(arg4)>
This permit you to write something as
overloaded
(auto arg) std::cout << arg << ' '; ,
(double arg) std::cout << std::fixed << arg << ' '; ,
(const std::string& arg) std::cout << std::quoted(arg) << ' '; ,
that in C++14 was
auto l1 = (auto arg) std::cout << arg << ' '; ;
auto l2 = (double arg) std::cout << std::fixed << arg << ' '; ;
auto l3 = (const std::string& arg) std::cout << std::quoted(arg) << ' ';
overloaded<decltype(l1), decltype(l2), decltype(l3)> ovl1, l2, l3;
add a comment |Â
up vote
5
down vote
What are the two lines declaring overloaded, just above int main(), mean?
The first one
template<class... Ts>
struct overloaded : Ts...
using Ts::operator()...; ;
is a classic class/struct declaration/definition/implementation. Valid from C++11 (because use variadic templates).
In this case, overload
inherit from all template parameters and enable (using
row) all inherited operator()
.
Unfortunately the variadic using
is available only starting from C++17.
The second one
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
is a "deduction guide" (see this page for more details) and it's a new C++17 feature.
In your case, the deduction guide say that when you write something as
auto ov = overloaded arg1, arg2, arg3, arg4 ;
or also
overloaded ov arg1, args, arg3, arg4 ;
ov
become a overloaded<decltype(arg1), decltype(arg2), decltype(arg3), decltype(arg4)>
This permit you to write something as
overloaded
(auto arg) std::cout << arg << ' '; ,
(double arg) std::cout << std::fixed << arg << ' '; ,
(const std::string& arg) std::cout << std::quoted(arg) << ' '; ,
that in C++14 was
auto l1 = (auto arg) std::cout << arg << ' '; ;
auto l2 = (double arg) std::cout << std::fixed << arg << ' '; ;
auto l3 = (const std::string& arg) std::cout << std::quoted(arg) << ' ';
overloaded<decltype(l1), decltype(l2), decltype(l3)> ovl1, l2, l3;
add a comment |Â
up vote
5
down vote
up vote
5
down vote
What are the two lines declaring overloaded, just above int main(), mean?
The first one
template<class... Ts>
struct overloaded : Ts...
using Ts::operator()...; ;
is a classic class/struct declaration/definition/implementation. Valid from C++11 (because use variadic templates).
In this case, overload
inherit from all template parameters and enable (using
row) all inherited operator()
.
Unfortunately the variadic using
is available only starting from C++17.
The second one
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
is a "deduction guide" (see this page for more details) and it's a new C++17 feature.
In your case, the deduction guide say that when you write something as
auto ov = overloaded arg1, arg2, arg3, arg4 ;
or also
overloaded ov arg1, args, arg3, arg4 ;
ov
become a overloaded<decltype(arg1), decltype(arg2), decltype(arg3), decltype(arg4)>
This permit you to write something as
overloaded
(auto arg) std::cout << arg << ' '; ,
(double arg) std::cout << std::fixed << arg << ' '; ,
(const std::string& arg) std::cout << std::quoted(arg) << ' '; ,
that in C++14 was
auto l1 = (auto arg) std::cout << arg << ' '; ;
auto l2 = (double arg) std::cout << std::fixed << arg << ' '; ;
auto l3 = (const std::string& arg) std::cout << std::quoted(arg) << ' ';
overloaded<decltype(l1), decltype(l2), decltype(l3)> ovl1, l2, l3;
What are the two lines declaring overloaded, just above int main(), mean?
The first one
template<class... Ts>
struct overloaded : Ts...
using Ts::operator()...; ;
is a classic class/struct declaration/definition/implementation. Valid from C++11 (because use variadic templates).
In this case, overload
inherit from all template parameters and enable (using
row) all inherited operator()
.
Unfortunately the variadic using
is available only starting from C++17.
The second one
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
is a "deduction guide" (see this page for more details) and it's a new C++17 feature.
In your case, the deduction guide say that when you write something as
auto ov = overloaded arg1, arg2, arg3, arg4 ;
or also
overloaded ov arg1, args, arg3, arg4 ;
ov
become a overloaded<decltype(arg1), decltype(arg2), decltype(arg3), decltype(arg4)>
This permit you to write something as
overloaded
(auto arg) std::cout << arg << ' '; ,
(double arg) std::cout << std::fixed << arg << ' '; ,
(const std::string& arg) std::cout << std::quoted(arg) << ' '; ,
that in C++14 was
auto l1 = (auto arg) std::cout << arg << ' '; ;
auto l2 = (double arg) std::cout << std::fixed << arg << ' '; ;
auto l3 = (const std::string& arg) std::cout << std::quoted(arg) << ' ';
overloaded<decltype(l1), decltype(l2), decltype(l3)> ovl1, l2, l3;
edited 52 mins ago
answered 1 hour ago
max66
29.7k63156
29.7k63156
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52523816%2fconfusing-templates-in-c17-example-of-stdvisit%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Anybody can shine some light on the initialization here? Why doesn't
overloads(/* some lambdas */);
work, butoverloads/* some lambdas */;
does? Notice the uniform initialization vs parentheses initialization.â Fureeish
22 mins ago