What are the ways to skip some overload combinations of variant types in std::visit?
Clash Royale CLAN TAG#URR8PPP
up vote
6
down vote
favorite
std::visit
supports multiple input variants. The code, however, should handle all combinations of the types from those variants.
Is there a way to skip not "meaningful" combinations?
for example:
template<class... Ts>
struct overloaded : Ts... using Ts::operator()...; ;
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main()
std::variant<int, float, char> v1 's' ;
std::variant<int, float, char> v2 10 ;
std::visit(overloaded
(int a, int b) ,
(int a, float b) ,
(int a, char b) ,
(float a, int b) ,
(float a, float b) ,
(float a, char b) ,
(char a, int b) ,
(char a, float b) ,
(char a, char b)
, v1, v2);
return 0;
is there a chance to implement only several important combinations, and "leave" the rest?
(of course right now the compiler will report nasty error if you forget to implement one combination...)
maybe generic lambdas?
std::visit(overloaded
(int a, int b) ,
(int a, float b) ,
(int a, char b) ,
(float a, int b) ,
(auto a, auto b) , // <<
, v1, v2);
That works, but I wonder if there's some better solution?
Update:
Here's the playground with the solutions mentioned in the answers:
http://coliru.stacked-crooked.com/a/78d9f2f25789bad2
c++ c++17
 |Â
show 3 more comments
up vote
6
down vote
favorite
std::visit
supports multiple input variants. The code, however, should handle all combinations of the types from those variants.
Is there a way to skip not "meaningful" combinations?
for example:
template<class... Ts>
struct overloaded : Ts... using Ts::operator()...; ;
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main()
std::variant<int, float, char> v1 's' ;
std::variant<int, float, char> v2 10 ;
std::visit(overloaded
(int a, int b) ,
(int a, float b) ,
(int a, char b) ,
(float a, int b) ,
(float a, float b) ,
(float a, char b) ,
(char a, int b) ,
(char a, float b) ,
(char a, char b)
, v1, v2);
return 0;
is there a chance to implement only several important combinations, and "leave" the rest?
(of course right now the compiler will report nasty error if you forget to implement one combination...)
maybe generic lambdas?
std::visit(overloaded
(int a, int b) ,
(int a, float b) ,
(int a, char b) ,
(float a, int b) ,
(auto a, auto b) , // <<
, v1, v2);
That works, but I wonder if there's some better solution?
Update:
Here's the playground with the solutions mentioned in the answers:
http://coliru.stacked-crooked.com/a/78d9f2f25789bad2
c++ c++17
1
"maybe generic lambdas" Umm did you try that? Are you looking for another solution than generic lambdas?
â Rakete1111
Aug 29 at 10:17
generic lambdas should do the job.
â Jarod42
Aug 29 at 10:19
yes, generic lambdas will work here, but I wonder if there's another solution. Generic lambdas should have lower precedence in the resolution set, so they will be chosen as the last resort... right?
â fen
Aug 29 at 10:20
1
Why don't you like generic lambdas here?
â Evg
Aug 29 at 10:23
I like it, but wondering about other options. So maybe the whole question is not asked correctly.
â fen
Aug 29 at 10:26
 |Â
show 3 more comments
up vote
6
down vote
favorite
up vote
6
down vote
favorite
std::visit
supports multiple input variants. The code, however, should handle all combinations of the types from those variants.
Is there a way to skip not "meaningful" combinations?
for example:
template<class... Ts>
struct overloaded : Ts... using Ts::operator()...; ;
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main()
std::variant<int, float, char> v1 's' ;
std::variant<int, float, char> v2 10 ;
std::visit(overloaded
(int a, int b) ,
(int a, float b) ,
(int a, char b) ,
(float a, int b) ,
(float a, float b) ,
(float a, char b) ,
(char a, int b) ,
(char a, float b) ,
(char a, char b)
, v1, v2);
return 0;
is there a chance to implement only several important combinations, and "leave" the rest?
(of course right now the compiler will report nasty error if you forget to implement one combination...)
maybe generic lambdas?
std::visit(overloaded
(int a, int b) ,
(int a, float b) ,
(int a, char b) ,
(float a, int b) ,
(auto a, auto b) , // <<
, v1, v2);
That works, but I wonder if there's some better solution?
Update:
Here's the playground with the solutions mentioned in the answers:
http://coliru.stacked-crooked.com/a/78d9f2f25789bad2
c++ c++17
std::visit
supports multiple input variants. The code, however, should handle all combinations of the types from those variants.
Is there a way to skip not "meaningful" combinations?
for example:
template<class... Ts>
struct overloaded : Ts... using Ts::operator()...; ;
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
int main()
std::variant<int, float, char> v1 's' ;
std::variant<int, float, char> v2 10 ;
std::visit(overloaded
(int a, int b) ,
(int a, float b) ,
(int a, char b) ,
(float a, int b) ,
(float a, float b) ,
(float a, char b) ,
(char a, int b) ,
(char a, float b) ,
(char a, char b)
, v1, v2);
return 0;
is there a chance to implement only several important combinations, and "leave" the rest?
(of course right now the compiler will report nasty error if you forget to implement one combination...)
maybe generic lambdas?
std::visit(overloaded
(int a, int b) ,
(int a, float b) ,
(int a, char b) ,
(float a, int b) ,
(auto a, auto b) , // <<
, v1, v2);
That works, but I wonder if there's some better solution?
Update:
Here's the playground with the solutions mentioned in the answers:
http://coliru.stacked-crooked.com/a/78d9f2f25789bad2
c++ c++17
edited Aug 29 at 11:06
asked Aug 29 at 10:15
fen
5,28131941
5,28131941
1
"maybe generic lambdas" Umm did you try that? Are you looking for another solution than generic lambdas?
â Rakete1111
Aug 29 at 10:17
generic lambdas should do the job.
â Jarod42
Aug 29 at 10:19
yes, generic lambdas will work here, but I wonder if there's another solution. Generic lambdas should have lower precedence in the resolution set, so they will be chosen as the last resort... right?
â fen
Aug 29 at 10:20
1
Why don't you like generic lambdas here?
â Evg
Aug 29 at 10:23
I like it, but wondering about other options. So maybe the whole question is not asked correctly.
â fen
Aug 29 at 10:26
 |Â
show 3 more comments
1
"maybe generic lambdas" Umm did you try that? Are you looking for another solution than generic lambdas?
â Rakete1111
Aug 29 at 10:17
generic lambdas should do the job.
â Jarod42
Aug 29 at 10:19
yes, generic lambdas will work here, but I wonder if there's another solution. Generic lambdas should have lower precedence in the resolution set, so they will be chosen as the last resort... right?
â fen
Aug 29 at 10:20
1
Why don't you like generic lambdas here?
â Evg
Aug 29 at 10:23
I like it, but wondering about other options. So maybe the whole question is not asked correctly.
â fen
Aug 29 at 10:26
1
1
"maybe generic lambdas" Umm did you try that? Are you looking for another solution than generic lambdas?
â Rakete1111
Aug 29 at 10:17
"maybe generic lambdas" Umm did you try that? Are you looking for another solution than generic lambdas?
â Rakete1111
Aug 29 at 10:17
generic lambdas should do the job.
â Jarod42
Aug 29 at 10:19
generic lambdas should do the job.
â Jarod42
Aug 29 at 10:19
yes, generic lambdas will work here, but I wonder if there's another solution. Generic lambdas should have lower precedence in the resolution set, so they will be chosen as the last resort... right?
â fen
Aug 29 at 10:20
yes, generic lambdas will work here, but I wonder if there's another solution. Generic lambdas should have lower precedence in the resolution set, so they will be chosen as the last resort... right?
â fen
Aug 29 at 10:20
1
1
Why don't you like generic lambdas here?
â Evg
Aug 29 at 10:23
Why don't you like generic lambdas here?
â Evg
Aug 29 at 10:23
I like it, but wondering about other options. So maybe the whole question is not asked correctly.
â fen
Aug 29 at 10:26
I like it, but wondering about other options. So maybe the whole question is not asked correctly.
â fen
Aug 29 at 10:26
 |Â
show 3 more comments
2 Answers
2
active
oldest
votes
up vote
7
down vote
accepted
Yes, generic lambdas are a very good solution. Your proposed solution literally works ad litteram.
Usual overload rules apply.
(auto a, auto b)
is equivalent in this sense with
template <class T1, class T2> auto foo(T1 a, T2 b) const;
Anything that doesn't match exactly one of the non-templated overloads will call the generic lambda.
You can mix things up a bit by providing something like (int a, auto b)
and (auto a, auto b)
. Still usual overload rules apply.
Or mix things up even more with <class T>(T a, T b)
(since C++20)
is there anything else we can use here? and is it guaranteed to work?
â fen
Aug 29 at 10:22
@fen C variadics I guess
â Rakete1111
Aug 29 at 10:27
1
@Rakete1111 let's not go the C way :)
â fen
Aug 29 at 10:32
so it's guaranteed to work because concrete overloads will be always chosen as the best viable functions rather than the templated (generic lambda) versions.
â fen
Aug 29 at 10:37
2
@fen yes. I am trying to think if there are any gotchas. The usual gotcha is that implicit conversion will go to the template, but it doesn't apply her because you have a clear type in thestd::variant
. So yes, it works as excepted (as far as I can see).
â bolov
Aug 29 at 10:41
 |Â
show 2 more comments
up vote
3
down vote
Another option would be to change overloaded
to something like this:
template<class... Ts>
struct overloaded_or_no_op : Ts...
using Ts::operator()...;
template<class... Us>
void operator()(const Us&...) const
;
template<class... Ts> overloaded_or_no_op(Ts...) -> overloaded_or_no_op<Ts...>;
nice! so we can add some other functionalities to the overloaded pattern. In your example, users would have to provide only "interesting" implementations and skip the rest.
â fen
Aug 29 at 10:35
5
I'd prefer having a separatenop
likeconstexpr auto nop = (auto const & ...)
and then explicitly mention it in the overload set given tooverloaded
â lisyarus
Aug 29 at 11:10
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
7
down vote
accepted
Yes, generic lambdas are a very good solution. Your proposed solution literally works ad litteram.
Usual overload rules apply.
(auto a, auto b)
is equivalent in this sense with
template <class T1, class T2> auto foo(T1 a, T2 b) const;
Anything that doesn't match exactly one of the non-templated overloads will call the generic lambda.
You can mix things up a bit by providing something like (int a, auto b)
and (auto a, auto b)
. Still usual overload rules apply.
Or mix things up even more with <class T>(T a, T b)
(since C++20)
is there anything else we can use here? and is it guaranteed to work?
â fen
Aug 29 at 10:22
@fen C variadics I guess
â Rakete1111
Aug 29 at 10:27
1
@Rakete1111 let's not go the C way :)
â fen
Aug 29 at 10:32
so it's guaranteed to work because concrete overloads will be always chosen as the best viable functions rather than the templated (generic lambda) versions.
â fen
Aug 29 at 10:37
2
@fen yes. I am trying to think if there are any gotchas. The usual gotcha is that implicit conversion will go to the template, but it doesn't apply her because you have a clear type in thestd::variant
. So yes, it works as excepted (as far as I can see).
â bolov
Aug 29 at 10:41
 |Â
show 2 more comments
up vote
7
down vote
accepted
Yes, generic lambdas are a very good solution. Your proposed solution literally works ad litteram.
Usual overload rules apply.
(auto a, auto b)
is equivalent in this sense with
template <class T1, class T2> auto foo(T1 a, T2 b) const;
Anything that doesn't match exactly one of the non-templated overloads will call the generic lambda.
You can mix things up a bit by providing something like (int a, auto b)
and (auto a, auto b)
. Still usual overload rules apply.
Or mix things up even more with <class T>(T a, T b)
(since C++20)
is there anything else we can use here? and is it guaranteed to work?
â fen
Aug 29 at 10:22
@fen C variadics I guess
â Rakete1111
Aug 29 at 10:27
1
@Rakete1111 let's not go the C way :)
â fen
Aug 29 at 10:32
so it's guaranteed to work because concrete overloads will be always chosen as the best viable functions rather than the templated (generic lambda) versions.
â fen
Aug 29 at 10:37
2
@fen yes. I am trying to think if there are any gotchas. The usual gotcha is that implicit conversion will go to the template, but it doesn't apply her because you have a clear type in thestd::variant
. So yes, it works as excepted (as far as I can see).
â bolov
Aug 29 at 10:41
 |Â
show 2 more comments
up vote
7
down vote
accepted
up vote
7
down vote
accepted
Yes, generic lambdas are a very good solution. Your proposed solution literally works ad litteram.
Usual overload rules apply.
(auto a, auto b)
is equivalent in this sense with
template <class T1, class T2> auto foo(T1 a, T2 b) const;
Anything that doesn't match exactly one of the non-templated overloads will call the generic lambda.
You can mix things up a bit by providing something like (int a, auto b)
and (auto a, auto b)
. Still usual overload rules apply.
Or mix things up even more with <class T>(T a, T b)
(since C++20)
Yes, generic lambdas are a very good solution. Your proposed solution literally works ad litteram.
Usual overload rules apply.
(auto a, auto b)
is equivalent in this sense with
template <class T1, class T2> auto foo(T1 a, T2 b) const;
Anything that doesn't match exactly one of the non-templated overloads will call the generic lambda.
You can mix things up a bit by providing something like (int a, auto b)
and (auto a, auto b)
. Still usual overload rules apply.
Or mix things up even more with <class T>(T a, T b)
(since C++20)
edited Aug 29 at 12:53
answered Aug 29 at 10:21
bolov
27.4k661119
27.4k661119
is there anything else we can use here? and is it guaranteed to work?
â fen
Aug 29 at 10:22
@fen C variadics I guess
â Rakete1111
Aug 29 at 10:27
1
@Rakete1111 let's not go the C way :)
â fen
Aug 29 at 10:32
so it's guaranteed to work because concrete overloads will be always chosen as the best viable functions rather than the templated (generic lambda) versions.
â fen
Aug 29 at 10:37
2
@fen yes. I am trying to think if there are any gotchas. The usual gotcha is that implicit conversion will go to the template, but it doesn't apply her because you have a clear type in thestd::variant
. So yes, it works as excepted (as far as I can see).
â bolov
Aug 29 at 10:41
 |Â
show 2 more comments
is there anything else we can use here? and is it guaranteed to work?
â fen
Aug 29 at 10:22
@fen C variadics I guess
â Rakete1111
Aug 29 at 10:27
1
@Rakete1111 let's not go the C way :)
â fen
Aug 29 at 10:32
so it's guaranteed to work because concrete overloads will be always chosen as the best viable functions rather than the templated (generic lambda) versions.
â fen
Aug 29 at 10:37
2
@fen yes. I am trying to think if there are any gotchas. The usual gotcha is that implicit conversion will go to the template, but it doesn't apply her because you have a clear type in thestd::variant
. So yes, it works as excepted (as far as I can see).
â bolov
Aug 29 at 10:41
is there anything else we can use here? and is it guaranteed to work?
â fen
Aug 29 at 10:22
is there anything else we can use here? and is it guaranteed to work?
â fen
Aug 29 at 10:22
@fen C variadics I guess
â Rakete1111
Aug 29 at 10:27
@fen C variadics I guess
â Rakete1111
Aug 29 at 10:27
1
1
@Rakete1111 let's not go the C way :)
â fen
Aug 29 at 10:32
@Rakete1111 let's not go the C way :)
â fen
Aug 29 at 10:32
so it's guaranteed to work because concrete overloads will be always chosen as the best viable functions rather than the templated (generic lambda) versions.
â fen
Aug 29 at 10:37
so it's guaranteed to work because concrete overloads will be always chosen as the best viable functions rather than the templated (generic lambda) versions.
â fen
Aug 29 at 10:37
2
2
@fen yes. I am trying to think if there are any gotchas. The usual gotcha is that implicit conversion will go to the template, but it doesn't apply her because you have a clear type in the
std::variant
. So yes, it works as excepted (as far as I can see).â bolov
Aug 29 at 10:41
@fen yes. I am trying to think if there are any gotchas. The usual gotcha is that implicit conversion will go to the template, but it doesn't apply her because you have a clear type in the
std::variant
. So yes, it works as excepted (as far as I can see).â bolov
Aug 29 at 10:41
 |Â
show 2 more comments
up vote
3
down vote
Another option would be to change overloaded
to something like this:
template<class... Ts>
struct overloaded_or_no_op : Ts...
using Ts::operator()...;
template<class... Us>
void operator()(const Us&...) const
;
template<class... Ts> overloaded_or_no_op(Ts...) -> overloaded_or_no_op<Ts...>;
nice! so we can add some other functionalities to the overloaded pattern. In your example, users would have to provide only "interesting" implementations and skip the rest.
â fen
Aug 29 at 10:35
5
I'd prefer having a separatenop
likeconstexpr auto nop = (auto const & ...)
and then explicitly mention it in the overload set given tooverloaded
â lisyarus
Aug 29 at 11:10
add a comment |Â
up vote
3
down vote
Another option would be to change overloaded
to something like this:
template<class... Ts>
struct overloaded_or_no_op : Ts...
using Ts::operator()...;
template<class... Us>
void operator()(const Us&...) const
;
template<class... Ts> overloaded_or_no_op(Ts...) -> overloaded_or_no_op<Ts...>;
nice! so we can add some other functionalities to the overloaded pattern. In your example, users would have to provide only "interesting" implementations and skip the rest.
â fen
Aug 29 at 10:35
5
I'd prefer having a separatenop
likeconstexpr auto nop = (auto const & ...)
and then explicitly mention it in the overload set given tooverloaded
â lisyarus
Aug 29 at 11:10
add a comment |Â
up vote
3
down vote
up vote
3
down vote
Another option would be to change overloaded
to something like this:
template<class... Ts>
struct overloaded_or_no_op : Ts...
using Ts::operator()...;
template<class... Us>
void operator()(const Us&...) const
;
template<class... Ts> overloaded_or_no_op(Ts...) -> overloaded_or_no_op<Ts...>;
Another option would be to change overloaded
to something like this:
template<class... Ts>
struct overloaded_or_no_op : Ts...
using Ts::operator()...;
template<class... Us>
void operator()(const Us&...) const
;
template<class... Ts> overloaded_or_no_op(Ts...) -> overloaded_or_no_op<Ts...>;
edited Aug 29 at 11:41
answered Aug 29 at 10:32
Evg
2,2351128
2,2351128
nice! so we can add some other functionalities to the overloaded pattern. In your example, users would have to provide only "interesting" implementations and skip the rest.
â fen
Aug 29 at 10:35
5
I'd prefer having a separatenop
likeconstexpr auto nop = (auto const & ...)
and then explicitly mention it in the overload set given tooverloaded
â lisyarus
Aug 29 at 11:10
add a comment |Â
nice! so we can add some other functionalities to the overloaded pattern. In your example, users would have to provide only "interesting" implementations and skip the rest.
â fen
Aug 29 at 10:35
5
I'd prefer having a separatenop
likeconstexpr auto nop = (auto const & ...)
and then explicitly mention it in the overload set given tooverloaded
â lisyarus
Aug 29 at 11:10
nice! so we can add some other functionalities to the overloaded pattern. In your example, users would have to provide only "interesting" implementations and skip the rest.
â fen
Aug 29 at 10:35
nice! so we can add some other functionalities to the overloaded pattern. In your example, users would have to provide only "interesting" implementations and skip the rest.
â fen
Aug 29 at 10:35
5
5
I'd prefer having a separate
nop
like constexpr auto nop = (auto const & ...)
and then explicitly mention it in the overload set given to overloaded
â lisyarus
Aug 29 at 11:10
I'd prefer having a separate
nop
like constexpr auto nop = (auto const & ...)
and then explicitly mention it in the overload set given to overloaded
â lisyarus
Aug 29 at 11:10
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%2f52074993%2fwhat-are-the-ways-to-skip-some-overload-combinations-of-variant-types-in-stdvi%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
1
"maybe generic lambdas" Umm did you try that? Are you looking for another solution than generic lambdas?
â Rakete1111
Aug 29 at 10:17
generic lambdas should do the job.
â Jarod42
Aug 29 at 10:19
yes, generic lambdas will work here, but I wonder if there's another solution. Generic lambdas should have lower precedence in the resolution set, so they will be chosen as the last resort... right?
â fen
Aug 29 at 10:20
1
Why don't you like generic lambdas here?
â Evg
Aug 29 at 10:23
I like it, but wondering about other options. So maybe the whole question is not asked correctly.
â fen
Aug 29 at 10:26