What are the ways to skip some overload combinations of variant types in std::visit?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
6
down vote

favorite
1












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







share|improve this question


















  • 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














up vote
6
down vote

favorite
1












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







share|improve this question


















  • 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












up vote
6
down vote

favorite
1









up vote
6
down vote

favorite
1






1





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







share|improve this question














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









share|improve this question













share|improve this question




share|improve this question








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












  • 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












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)






share|improve this answer






















  • 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 the std::variant. So yes, it works as excepted (as far as I can see).
    – bolov
    Aug 29 at 10:41


















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...>;





share|improve this answer






















  • 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 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










Your Answer





StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















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






























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)






share|improve this answer






















  • 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 the std::variant. So yes, it works as excepted (as far as I can see).
    – bolov
    Aug 29 at 10:41















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)






share|improve this answer






















  • 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 the std::variant. So yes, it works as excepted (as far as I can see).
    – bolov
    Aug 29 at 10:41













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)






share|improve this answer














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)







share|improve this answer














share|improve this answer



share|improve this answer








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 the std::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











  • @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 the std::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













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...>;





share|improve this answer






















  • 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 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














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...>;





share|improve this answer






















  • 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 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












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...>;





share|improve this answer














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...>;






share|improve this answer














share|improve this answer



share|improve this answer








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 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
















  • 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 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















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

















 

draft saved


draft discarded















































 


draft saved


draft discarded














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













































































Comments

Popular posts from this blog

What does second last employer means? [closed]

Installing NextGIS Connect into QGIS 3?

One-line joke