Overload resolution for inherited functions
up vote
52
down vote
favorite
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
add a comment |
up vote
52
down vote
favorite
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
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 frombase<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
add a comment |
up vote
52
down vote
favorite
up vote
52
down vote
favorite
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
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
c++ templates inheritance lambda overloading
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 frombase<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
add a comment |
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 frombase<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
add a comment |
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
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 ofthis
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
add a comment |
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
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 ofthis
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
add a comment |
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
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 ofthis
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
add a comment |
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
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
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 ofthis
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
add a comment |
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 ofthis
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
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
Required, but never shown
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
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
Required, but never shown
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
Required, but never shown
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
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
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 frombase<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