Function template and regular overloads

Multi tool use
The following code has a couple of regular function overloads, and - now - a template function intended as a catch-all if no overload is suitable.
It almost works as I want, except that using derived classes (which previously ended up in the regular overload) get handled by the function template instead.
#include <iostream>
class Base { };
class AnotherBase { };
class Derv : public Base{ };
class Derv2 : public Base { };
class DervDerv : public Derv { };
void f(const Base &b)
{
printf("b(Base)n");
}
void f(const Derv &b)
{
printf("b(Derv)n");
}
template<class T> void f(const T& t)
{
printf("b(template)n");
}
int main() {
f(Base());
f(AnotherBase());
f(Derv());
f(Derv2());
f(DervDerv());
return 0;
}
So the output I get is this...
b(Base)
b(template)
b(Derv)
b(template)
b(template)
... when what I'd naively expected was this:
b(Base)
b(template)
b(Derv)
b(Base)
b(Derv)
Is a function overload of a base class really ranked as "lower quality" than a function template? If so, is there an easy way to change this?
https://ideone.com/jD2lgz
c++ overload-resolution function-templates
add a comment |
The following code has a couple of regular function overloads, and - now - a template function intended as a catch-all if no overload is suitable.
It almost works as I want, except that using derived classes (which previously ended up in the regular overload) get handled by the function template instead.
#include <iostream>
class Base { };
class AnotherBase { };
class Derv : public Base{ };
class Derv2 : public Base { };
class DervDerv : public Derv { };
void f(const Base &b)
{
printf("b(Base)n");
}
void f(const Derv &b)
{
printf("b(Derv)n");
}
template<class T> void f(const T& t)
{
printf("b(template)n");
}
int main() {
f(Base());
f(AnotherBase());
f(Derv());
f(Derv2());
f(DervDerv());
return 0;
}
So the output I get is this...
b(Base)
b(template)
b(Derv)
b(template)
b(template)
... when what I'd naively expected was this:
b(Base)
b(template)
b(Derv)
b(Base)
b(Derv)
Is a function overload of a base class really ranked as "lower quality" than a function template? If so, is there an easy way to change this?
https://ideone.com/jD2lgz
c++ overload-resolution function-templates
add a comment |
The following code has a couple of regular function overloads, and - now - a template function intended as a catch-all if no overload is suitable.
It almost works as I want, except that using derived classes (which previously ended up in the regular overload) get handled by the function template instead.
#include <iostream>
class Base { };
class AnotherBase { };
class Derv : public Base{ };
class Derv2 : public Base { };
class DervDerv : public Derv { };
void f(const Base &b)
{
printf("b(Base)n");
}
void f(const Derv &b)
{
printf("b(Derv)n");
}
template<class T> void f(const T& t)
{
printf("b(template)n");
}
int main() {
f(Base());
f(AnotherBase());
f(Derv());
f(Derv2());
f(DervDerv());
return 0;
}
So the output I get is this...
b(Base)
b(template)
b(Derv)
b(template)
b(template)
... when what I'd naively expected was this:
b(Base)
b(template)
b(Derv)
b(Base)
b(Derv)
Is a function overload of a base class really ranked as "lower quality" than a function template? If so, is there an easy way to change this?
https://ideone.com/jD2lgz
c++ overload-resolution function-templates
The following code has a couple of regular function overloads, and - now - a template function intended as a catch-all if no overload is suitable.
It almost works as I want, except that using derived classes (which previously ended up in the regular overload) get handled by the function template instead.
#include <iostream>
class Base { };
class AnotherBase { };
class Derv : public Base{ };
class Derv2 : public Base { };
class DervDerv : public Derv { };
void f(const Base &b)
{
printf("b(Base)n");
}
void f(const Derv &b)
{
printf("b(Derv)n");
}
template<class T> void f(const T& t)
{
printf("b(template)n");
}
int main() {
f(Base());
f(AnotherBase());
f(Derv());
f(Derv2());
f(DervDerv());
return 0;
}
So the output I get is this...
b(Base)
b(template)
b(Derv)
b(template)
b(template)
... when what I'd naively expected was this:
b(Base)
b(template)
b(Derv)
b(Base)
b(Derv)
Is a function overload of a base class really ranked as "lower quality" than a function template? If so, is there an easy way to change this?
https://ideone.com/jD2lgz
c++ overload-resolution function-templates
c++ overload-resolution function-templates
asked Dec 30 '18 at 12:08
RoddyRoddy
45.8k35146239
45.8k35146239
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());
, a compiler will synthesize a declaration like this one from your function template:
void f(const Derv2& t);
Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &)
is a better match than f(const Base &)
when you write f(Derv());
.
A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:
template<class T>
auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
{
printf("b(template)n");
}
That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.
Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?
– Roddy
Dec 30 '18 at 12:38
@Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.
– StoryTeller
Dec 30 '18 at 12:39
As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As isstd::is_convertible<T*, Base*>::value
, which can be used instead ofis_base_of
. Look those up.
– StoryTeller
Dec 30 '18 at 12:41
add a comment |
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',
autoActivateHeartbeat: false,
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
});
}
});
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%2f53977457%2ffunction-template-and-regular-overloads%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
It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());
, a compiler will synthesize a declaration like this one from your function template:
void f(const Derv2& t);
Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &)
is a better match than f(const Base &)
when you write f(Derv());
.
A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:
template<class T>
auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
{
printf("b(template)n");
}
That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.
Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?
– Roddy
Dec 30 '18 at 12:38
@Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.
– StoryTeller
Dec 30 '18 at 12:39
As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As isstd::is_convertible<T*, Base*>::value
, which can be used instead ofis_base_of
. Look those up.
– StoryTeller
Dec 30 '18 at 12:41
add a comment |
It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());
, a compiler will synthesize a declaration like this one from your function template:
void f(const Derv2& t);
Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &)
is a better match than f(const Base &)
when you write f(Derv());
.
A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:
template<class T>
auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
{
printf("b(template)n");
}
That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.
Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?
– Roddy
Dec 30 '18 at 12:38
@Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.
– StoryTeller
Dec 30 '18 at 12:39
As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As isstd::is_convertible<T*, Base*>::value
, which can be used instead ofis_base_of
. Look those up.
– StoryTeller
Dec 30 '18 at 12:41
add a comment |
It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());
, a compiler will synthesize a declaration like this one from your function template:
void f(const Derv2& t);
Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &)
is a better match than f(const Base &)
when you write f(Derv());
.
A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:
template<class T>
auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
{
printf("b(template)n");
}
That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.
It's not about "quality". It's about conversions, just like it is with any other overload. To do overload resolution on the call to f(Derv2());
, a compiler will synthesize a declaration like this one from your function template:
void f(const Derv2& t);
Which it pits against the other declared overloads. This overload gets picked for the exact same reason f(const Derv &)
is a better match than f(const Base &)
when you write f(Derv());
.
A "catch-all" template will do just that, it will catch everything for which there isn't an exact user-defined overload. If you want to prevent that, you need to constrain the template with meta programming. A simple trick that relies on SFINAE would look like this:
template<class T>
auto f(const T& t) -> std::enable_if_t<!std::is_convertible<T*, Base*>::value>
{
printf("b(template)n");
}
That produces the exact output you expected. Though obviously, you'd need to know what to constrain against in advance.
edited Dec 30 '18 at 12:47
answered Dec 30 '18 at 12:21
StoryTellerStoryTeller
97.1k12198264
97.1k12198264
Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?
– Roddy
Dec 30 '18 at 12:38
@Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.
– StoryTeller
Dec 30 '18 at 12:39
As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As isstd::is_convertible<T*, Base*>::value
, which can be used instead ofis_base_of
. Look those up.
– StoryTeller
Dec 30 '18 at 12:41
add a comment |
Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?
– Roddy
Dec 30 '18 at 12:38
@Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.
– StoryTeller
Dec 30 '18 at 12:39
As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As isstd::is_convertible<T*, Base*>::value
, which can be used instead ofis_base_of
. Look those up.
– StoryTeller
Dec 30 '18 at 12:41
Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?
– Roddy
Dec 30 '18 at 12:38
Thanks. Forgot to mention I'm stuck in a C++03 world, so I think your suggestion won't work. Would replacing the regular overloads with template specializations help?
– Roddy
Dec 30 '18 at 12:38
@Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.
– StoryTeller
Dec 30 '18 at 12:39
@Roddy - No. The primary would still be a better match, because the arguments will match exactly. The overloads turned specializations won't even be considered. As a matter of fact, you would probably be worse off. Specializations don't participate in overload resolution.
– StoryTeller
Dec 30 '18 at 12:39
As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As is
std::is_convertible<T*, Base*>::value
, which can be used instead of is_base_of
. Look those up.– StoryTeller
Dec 30 '18 at 12:41
As for C++03, this can be adapted. Boost had enable_if for ages before it was added to the standard library. And it's dead simple to implement. As is
std::is_convertible<T*, Base*>::value
, which can be used instead of is_base_of
. Look those up.– StoryTeller
Dec 30 '18 at 12:41
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
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%2f53977457%2ffunction-template-and-regular-overloads%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
5h,DfUppuPUuwuTTJ,c31 pDoe4VOX0zsJG c1rZTTwA1 bYIHBd3562IshjRwG4QiZU8uu1QiXJznj,ERgYddNp