Overload resolution for inherited functions











up vote
52
down vote

favorite
14












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 poc{l_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. Therefore, 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 Microsoft Visual C++, Clang and GCC (all in their latest versions).



Edit:




  • MSVC 15.8.9

  • GCC 9.0.0 (via Wandbox)

  • Clang 8.0.0 (via Wandbox)










share|improve this question




















  • 3




    quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
    – user463035818
    Nov 6 at 14:01






  • 1




    @YSC It's not CRTP, in CRTP, derived inherits from base<derived>.
    – Walter
    Nov 6 at 14:39










  • @Walter Ho that's true. I let myself carried away by that code snippet. This is funny how C++ nerds as myself can become quite ecstatic with so little :)
    – YSC
    Nov 6 at 14:43






  • 3




    Consider an edit: Replace all in their latest versions with their actual versions, so people in the future have a good reference point.
    – studog
    Nov 6 at 21:13










  • @studog Good point, I added the versions. Since this concept seems to attract a bit of attention, I'm thinking of writing blog post about how we actually plan to use it.
    – LcdDrm
    Nov 7 at 6:00















up vote
52
down vote

favorite
14












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 poc{l_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. Therefore, 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 Microsoft Visual C++, Clang and GCC (all in their latest versions).



Edit:




  • MSVC 15.8.9

  • GCC 9.0.0 (via Wandbox)

  • Clang 8.0.0 (via Wandbox)










share|improve this question




















  • 3




    quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
    – user463035818
    Nov 6 at 14:01






  • 1




    @YSC It's not CRTP, in CRTP, derived inherits from base<derived>.
    – Walter
    Nov 6 at 14:39










  • @Walter Ho that's true. I let myself carried away by that code snippet. This is funny how C++ nerds as myself can become quite ecstatic with so little :)
    – YSC
    Nov 6 at 14:43






  • 3




    Consider an edit: Replace all in their latest versions with their actual versions, so people in the future have a good reference point.
    – studog
    Nov 6 at 21:13










  • @studog Good point, I added the versions. Since this concept seems to attract a bit of attention, I'm thinking of writing blog post about how we actually plan to use it.
    – LcdDrm
    Nov 7 at 6:00













up vote
52
down vote

favorite
14









up vote
52
down vote

favorite
14






14





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 poc{l_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. Therefore, 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 Microsoft Visual C++, Clang and GCC (all in their latest versions).



Edit:




  • MSVC 15.8.9

  • GCC 9.0.0 (via Wandbox)

  • Clang 8.0.0 (via Wandbox)










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 poc{l_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. Therefore, 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 Microsoft Visual C++, Clang and GCC (all in their latest versions).



Edit:




  • MSVC 15.8.9

  • GCC 9.0.0 (via Wandbox)

  • Clang 8.0.0 (via Wandbox)







c++ templates inheritance lambda overloading






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 7 at 5:58

























asked Nov 6 at 13:54









LcdDrm

387210




387210








  • 3




    quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
    – user463035818
    Nov 6 at 14:01






  • 1




    @YSC It's not CRTP, in CRTP, derived inherits from base<derived>.
    – Walter
    Nov 6 at 14:39










  • @Walter Ho that's true. I let myself carried away by that code snippet. This is funny how C++ nerds as myself can become quite ecstatic with so little :)
    – YSC
    Nov 6 at 14:43






  • 3




    Consider an edit: Replace all in their latest versions with their actual versions, so people in the future have a good reference point.
    – studog
    Nov 6 at 21:13










  • @studog Good point, I added the versions. Since this concept seems to attract a bit of attention, I'm thinking of writing blog post about how we actually plan to use it.
    – LcdDrm
    Nov 7 at 6:00














  • 3




    quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
    – user463035818
    Nov 6 at 14:01






  • 1




    @YSC It's not CRTP, in CRTP, derived inherits from base<derived>.
    – Walter
    Nov 6 at 14:39










  • @Walter Ho that's true. I let myself carried away by that code snippet. This is funny how C++ nerds as myself can become quite ecstatic with so little :)
    – YSC
    Nov 6 at 14:43






  • 3




    Consider an edit: Replace all in their latest versions with their actual versions, so people in the future have a good reference point.
    – studog
    Nov 6 at 21:13










  • @studog Good point, I added the versions. Since this concept seems to attract a bit of attention, I'm thinking of writing blog post about how we actually plan to use it.
    – LcdDrm
    Nov 7 at 6:00








3




3




quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
– user463035818
Nov 6 at 14:01




quite an interesting thing you have there. If you dont mind I will steal the idea (just to have some fun with it ;)
– user463035818
Nov 6 at 14:01




1




1




@YSC It's not CRTP, in CRTP, derived inherits from base<derived>.
– Walter
Nov 6 at 14:39




@YSC It's not CRTP, in CRTP, derived inherits from base<derived>.
– Walter
Nov 6 at 14:39












@Walter Ho that's true. I let myself carried away by that code snippet. This is funny how C++ nerds as myself can become quite ecstatic with so little :)
– YSC
Nov 6 at 14:43




@Walter Ho that's true. I let myself carried away by that code snippet. This is funny how C++ nerds as myself can become quite ecstatic with so little :)
– YSC
Nov 6 at 14:43




3




3




Consider an edit: Replace all in their latest versions with their actual versions, so people in the future have a good reference point.
– studog
Nov 6 at 21:13




Consider an edit: Replace all in their latest versions with their actual versions, so people in the future have a good reference point.
– studog
Nov 6 at 21:13












@studog Good point, I added the versions. Since this concept seems to attract a bit of attention, I'm thinking of writing blog post about how we actually plan to use it.
– LcdDrm
Nov 7 at 6:00




@studog Good point, I added the versions. Since this concept seems to attract a bit of attention, I'm thinking of writing blog post about how we actually plan to use it.
– LcdDrm
Nov 7 at 6:00












1 Answer
1






active

oldest

votes

















up vote
43
down vote



accepted










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|improve this answer























  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    Nov 6 at 14:01






  • 5




    @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
    Nov 6 at 14:07






  • 6




    Just like non-member overload resolution
    – Caleth
    Nov 6 at 14:09











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















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
43
down vote



accepted










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|improve this answer























  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    Nov 6 at 14:01






  • 5




    @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
    Nov 6 at 14:07






  • 6




    Just like non-member overload resolution
    – Caleth
    Nov 6 at 14:09















up vote
43
down vote



accepted










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|improve this answer























  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    Nov 6 at 14:01






  • 5




    @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
    Nov 6 at 14:07






  • 6




    Just like non-member overload resolution
    – Caleth
    Nov 6 at 14:09













up vote
43
down vote



accepted







up vote
43
down vote



accepted






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|improve this answer














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|improve this answer














share|improve this answer



share|improve this answer








edited Nov 6 at 20:53









Peter Mortensen

13.3k1983111




13.3k1983111










answered Nov 6 at 13:58









Quentin

43.2k580136




43.2k580136












  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    Nov 6 at 14:01






  • 5




    @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
    Nov 6 at 14:07






  • 6




    Just like non-member overload resolution
    – Caleth
    Nov 6 at 14:09


















  • So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
    – NathanOliver
    Nov 6 at 14:01






  • 5




    @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
    Nov 6 at 14:07






  • 6




    Just like non-member overload resolution
    – Caleth
    Nov 6 at 14:09
















So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
– NathanOliver
Nov 6 at 14:01




So in this case const qualification trumps template instantiation, and it will stamp out the template to not make *this const?
– NathanOliver
Nov 6 at 14:01




5




5




@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
Nov 6 at 14:07




@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
Nov 6 at 14:07




6




6




Just like non-member overload resolution
– Caleth
Nov 6 at 14:09




Just like non-member overload resolution
– Caleth
Nov 6 at 14:09


















 

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















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

Tangent Lines Diagram Along Smooth Curve

Yusuf al-Mu'taman ibn Hud

Zucchini