Overload Resolution for inherited functions

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











up vote
17
down vote

favorite
5












I want to have a struct that takes an arbitrary number of lambdas and serve as a central calling point for all their call operators.



If the call operator is invoked with an argument list that doesn't match any of the lambdas given on construction, a default call operator should be called.



I thought the following code would accomplish exactly this. The call operator for every lambda is "lifted" into the Poc class via using.



template <typename ...Lambdas>
struct Poc : Lambdas...

using Lambdas::operator() ...; //lift the lambda operators into the class

template <typename ...Ts>
auto operator() (Ts...)

std::cout << "general call" << std::endl;


;

//deduction guide
template <typename ...Ts>
Poc(Ts... ts)->Poc<Ts...>;

int main()

auto l_int = (int) std::cout << "int" << std::endl; ;

Poc pocl_int;
poc(1);//calls the default operator. why?

return 0;



When I don't have the default call operator in the struct, everything works as expected (with valid argument lists). If I add it to the struct (as in the code above), the default operator gets called everytime, no matter which arguments I call it with.



In my understanding, the lambda-call-operators and the structs (default)call-operator are present in the same scope. Therefor, they should all be looked at for the overload resolution. Since the lamdba-operator is more specific than the generic default operator, it should be chosen.



Apparently that is not the case. Why is that?



I tested on MSVC, clang and gcc (all in their latest versions).










share|improve this question



















  • 2




    quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
    – user463035818
    26 mins ago










  • This is the first instance of variadic CRTP I see :)
    – YSC
    10 mins ago














up vote
17
down vote

favorite
5












I want to have a struct that takes an arbitrary number of lambdas and serve as a central calling point for all their call operators.



If the call operator is invoked with an argument list that doesn't match any of the lambdas given on construction, a default call operator should be called.



I thought the following code would accomplish exactly this. The call operator for every lambda is "lifted" into the Poc class via using.



template <typename ...Lambdas>
struct Poc : Lambdas...

using Lambdas::operator() ...; //lift the lambda operators into the class

template <typename ...Ts>
auto operator() (Ts...)

std::cout << "general call" << std::endl;


;

//deduction guide
template <typename ...Ts>
Poc(Ts... ts)->Poc<Ts...>;

int main()

auto l_int = (int) std::cout << "int" << std::endl; ;

Poc pocl_int;
poc(1);//calls the default operator. why?

return 0;



When I don't have the default call operator in the struct, everything works as expected (with valid argument lists). If I add it to the struct (as in the code above), the default operator gets called everytime, no matter which arguments I call it with.



In my understanding, the lambda-call-operators and the structs (default)call-operator are present in the same scope. Therefor, they should all be looked at for the overload resolution. Since the lamdba-operator is more specific than the generic default operator, it should be chosen.



Apparently that is not the case. Why is that?



I tested on MSVC, clang and gcc (all in their latest versions).










share|improve this question



















  • 2




    quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
    – user463035818
    26 mins ago










  • This is the first instance of variadic CRTP I see :)
    – YSC
    10 mins ago












up vote
17
down vote

favorite
5









up vote
17
down vote

favorite
5






5





I want to have a struct that takes an arbitrary number of lambdas and serve as a central calling point for all their call operators.



If the call operator is invoked with an argument list that doesn't match any of the lambdas given on construction, a default call operator should be called.



I thought the following code would accomplish exactly this. The call operator for every lambda is "lifted" into the Poc class via using.



template <typename ...Lambdas>
struct Poc : Lambdas...

using Lambdas::operator() ...; //lift the lambda operators into the class

template <typename ...Ts>
auto operator() (Ts...)

std::cout << "general call" << std::endl;


;

//deduction guide
template <typename ...Ts>
Poc(Ts... ts)->Poc<Ts...>;

int main()

auto l_int = (int) std::cout << "int" << std::endl; ;

Poc pocl_int;
poc(1);//calls the default operator. why?

return 0;



When I don't have the default call operator in the struct, everything works as expected (with valid argument lists). If I add it to the struct (as in the code above), the default operator gets called everytime, no matter which arguments I call it with.



In my understanding, the lambda-call-operators and the structs (default)call-operator are present in the same scope. Therefor, they should all be looked at for the overload resolution. Since the lamdba-operator is more specific than the generic default operator, it should be chosen.



Apparently that is not the case. Why is that?



I tested on MSVC, clang and gcc (all in their latest versions).










share|improve this question















I want to have a struct that takes an arbitrary number of lambdas and serve as a central calling point for all their call operators.



If the call operator is invoked with an argument list that doesn't match any of the lambdas given on construction, a default call operator should be called.



I thought the following code would accomplish exactly this. The call operator for every lambda is "lifted" into the Poc class via using.



template <typename ...Lambdas>
struct Poc : Lambdas...

using Lambdas::operator() ...; //lift the lambda operators into the class

template <typename ...Ts>
auto operator() (Ts...)

std::cout << "general call" << std::endl;


;

//deduction guide
template <typename ...Ts>
Poc(Ts... ts)->Poc<Ts...>;

int main()

auto l_int = (int) std::cout << "int" << std::endl; ;

Poc pocl_int;
poc(1);//calls the default operator. why?

return 0;



When I don't have the default call operator in the struct, everything works as expected (with valid argument lists). If I add it to the struct (as in the code above), the default operator gets called everytime, no matter which arguments I call it with.



In my understanding, the lambda-call-operators and the structs (default)call-operator are present in the same scope. Therefor, they should all be looked at for the overload resolution. Since the lamdba-operator is more specific than the generic default operator, it should be chosen.



Apparently that is not the case. Why is that?



I tested on MSVC, clang and gcc (all in their latest versions).







c++ templates inheritance lambda overloading






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 26 mins ago









NathanOliver

81.1k15110170




81.1k15110170










asked 33 mins ago









LcdDrm

21718




21718







  • 2




    quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
    – user463035818
    26 mins ago










  • This is the first instance of variadic CRTP I see :)
    – YSC
    10 mins ago












  • 2




    quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
    – user463035818
    26 mins ago










  • This is the first instance of variadic CRTP I see :)
    – YSC
    10 mins ago







2




2




quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
– user463035818
26 mins ago




quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
– user463035818
26 mins ago












This is the first instance of variadic CRTP I see :)
– YSC
10 mins ago




This is the first instance of variadic CRTP I see :)
– YSC
10 mins ago












1 Answer
1






active

oldest

votes

















up vote
18
down vote



accepted










Thanks for the MCVE!



It's simple when you spot it: your operator is not const-qualified, while the lambda's one is (unless you define the lambda as mutable). Hence, it is a better match for your non-const instance of Poc.



Just add the missingconst:



auto operator() (Ts...) const




share




















  • Thanks! I would never have figured that out. I'll accept as an answer once the time limit is over.
    – LcdDrm
    27 mins ago






  • 3




    Nicely spotted!
    – lubgr
    27 mins ago










  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    27 mins ago






  • 2




    @NathanOliver yes, this constitutes an implicit conversion of this which ranks the non-template operator lower. Pardon me if I don't go spelunking through the overload resolution standardese and keep my "just qualify everything equally and all'll be good" stance ;)
    – Quentin
    21 mins ago






  • 3




    Just like non-member overload resolution
    – Caleth
    18 mins ago










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: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
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%2f53173336%2foverload-resolution-for-inherited-functions%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
18
down vote



accepted










Thanks for the MCVE!



It's simple when you spot it: your operator is not const-qualified, while the lambda's one is (unless you define the lambda as mutable). Hence, it is a better match for your non-const instance of Poc.



Just add the missingconst:



auto operator() (Ts...) const




share




















  • Thanks! I would never have figured that out. I'll accept as an answer once the time limit is over.
    – LcdDrm
    27 mins ago






  • 3




    Nicely spotted!
    – lubgr
    27 mins ago










  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    27 mins ago






  • 2




    @NathanOliver yes, this constitutes an implicit conversion of this which ranks the non-template operator lower. Pardon me if I don't go spelunking through the overload resolution standardese and keep my "just qualify everything equally and all'll be good" stance ;)
    – Quentin
    21 mins ago






  • 3




    Just like non-member overload resolution
    – Caleth
    18 mins ago














up vote
18
down vote



accepted










Thanks for the MCVE!



It's simple when you spot it: your operator is not const-qualified, while the lambda's one is (unless you define the lambda as mutable). Hence, it is a better match for your non-const instance of Poc.



Just add the missingconst:



auto operator() (Ts...) const




share




















  • Thanks! I would never have figured that out. I'll accept as an answer once the time limit is over.
    – LcdDrm
    27 mins ago






  • 3




    Nicely spotted!
    – lubgr
    27 mins ago










  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    27 mins ago






  • 2




    @NathanOliver yes, this constitutes an implicit conversion of this which ranks the non-template operator lower. Pardon me if I don't go spelunking through the overload resolution standardese and keep my "just qualify everything equally and all'll be good" stance ;)
    – Quentin
    21 mins ago






  • 3




    Just like non-member overload resolution
    – Caleth
    18 mins ago












up vote
18
down vote



accepted







up vote
18
down vote



accepted






Thanks for the MCVE!



It's simple when you spot it: your operator is not const-qualified, while the lambda's one is (unless you define the lambda as mutable). Hence, it is a better match for your non-const instance of Poc.



Just add the missingconst:



auto operator() (Ts...) const




share












Thanks for the MCVE!



It's simple when you spot it: your operator is not const-qualified, while the lambda's one is (unless you define the lambda as mutable). Hence, it is a better match for your non-const instance of Poc.



Just add the missingconst:



auto operator() (Ts...) const





share











share


share










answered 29 mins ago









Quentin

42.8k575132




42.8k575132











  • Thanks! I would never have figured that out. I'll accept as an answer once the time limit is over.
    – LcdDrm
    27 mins ago






  • 3




    Nicely spotted!
    – lubgr
    27 mins ago










  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    27 mins ago






  • 2




    @NathanOliver yes, this constitutes an implicit conversion of this which ranks the non-template operator lower. Pardon me if I don't go spelunking through the overload resolution standardese and keep my "just qualify everything equally and all'll be good" stance ;)
    – Quentin
    21 mins ago






  • 3




    Just like non-member overload resolution
    – Caleth
    18 mins ago
















  • Thanks! I would never have figured that out. I'll accept as an answer once the time limit is over.
    – LcdDrm
    27 mins ago






  • 3




    Nicely spotted!
    – lubgr
    27 mins ago










  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    27 mins ago






  • 2




    @NathanOliver yes, this constitutes an implicit conversion of this which ranks the non-template operator lower. Pardon me if I don't go spelunking through the overload resolution standardese and keep my "just qualify everything equally and all'll be good" stance ;)
    – Quentin
    21 mins ago






  • 3




    Just like non-member overload resolution
    – Caleth
    18 mins ago















Thanks! I would never have figured that out. I'll accept as an answer once the time limit is over.
– LcdDrm
27 mins ago




Thanks! I would never have figured that out. I'll accept as an answer once the time limit is over.
– LcdDrm
27 mins ago




3




3




Nicely spotted!
– lubgr
27 mins ago




Nicely spotted!
– lubgr
27 mins ago












So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
– NathanOliver
27 mins ago




So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
– NathanOliver
27 mins ago




2




2




@NathanOliver yes, this constitutes an implicit conversion of this which ranks the non-template operator lower. Pardon me if I don't go spelunking through the overload resolution standardese and keep my "just qualify everything equally and all'll be good" stance ;)
– Quentin
21 mins ago




@NathanOliver yes, this constitutes an implicit conversion of this which ranks the non-template operator lower. Pardon me if I don't go spelunking through the overload resolution standardese and keep my "just qualify everything equally and all'll be good" stance ;)
– Quentin
21 mins ago




3




3




Just like non-member overload resolution
– Caleth
18 mins ago




Just like non-member overload resolution
– Caleth
18 mins ago

















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53173336%2foverload-resolution-for-inherited-functions%23new-answer', 'question_page');

);

Post as a guest













































































Comments

Popular posts from this blog

What does second last employer means? [closed]

List of Gilmore Girls characters

Confectionery