Why is Overload Resolution favoring unconstrained template function over a more specific one?function overload matching template template“Overload” function template based on function object operator() signature in C++98Overload resolution and partial template orderingWhy this function overloading fails in C++?Overloaded operator ambiguity on Clang but not on GCC, which one is correct?Error while operator overloading (error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream<char>’ and ‘const char [2]’)C++ class template, how to overload [ ] operator in a specific stuation?Template template parameters - why are they needed in this case?C++11 ambiguous overload when calling variadic function templateAmbiguous Overload For operator “<<”
What is the theme of analysis?
Any gotchas in buying second-hand sanitary ware?
New Site Design!
Why did the Death Eaters wait to reopen the Chamber of Secrets?
What do I need to do, tax-wise, for a sudden windfall?
Print the phrase "And she said, 'But that's his.'" using only the alphabet
Can I get a photo of an Ancient Arrow?
What does the "titan" monster tag mean?
Why not make one big cpu core?
What game uses dice with compass point arrows, forbidden signs, explosions, arrows and targeting reticles?
DBCC SHRINKFILE on the distribution database
What's the reason for the decade jump in the recent X-Men trilogy?
Parsing text written the millitext font
Can an escape pod land on Earth from orbit and not be immediately detected?
Will users know a CardView is clickable
What is the color associated with lukewarm?
Parallelized for loop in Bash
Why is C++ template use not recommended in space/radiated environment?
Does every chapter have to "blow the reader away" so to speak?
How can this shape perfectly cover a cube?
I sent an angry e-mail to my interviewers about a conflict at my home institution. Could this affect my application?
Placement of positioning lights on A320 winglets
Interview was just a one hour panel. Got an offer the next day; do I accept or is this a red flag?
Loop counter not interpreted as number
Why is Overload Resolution favoring unconstrained template function over a more specific one?
function overload matching template template“Overload” function template based on function object operator() signature in C++98Overload resolution and partial template orderingWhy this function overloading fails in C++?Overloaded operator ambiguity on Clang but not on GCC, which one is correct?Error while operator overloading (error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream<char>’ and ‘const char [2]’)C++ class template, how to overload [ ] operator in a specific stuation?Template template parameters - why are they needed in this case?C++11 ambiguous overload when calling variadic function templateAmbiguous Overload For operator “<<”
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I have this minimal expression template library with a multiplication, i.e.
template <typename T, typename U>
struct mul
const T &v1;
const U &v2;
;
template <typename T, typename U>
mul<T, U> operator*(const T &one, const U &two)
std::cout << " called: mul<T, U> operator*(const T &one, const T &two)n";
return mul<T, U>one, two;
and transpose, i.e.
template <typename T>
struct transpose
const T &t;
;
template <typename T>
transpose<T> tran(const T &one)
return transpose<T>one;
I will introduce some types A
and B
, where the latter is a subclass of the former:
template <typename T>
struct A
T elem;
;
template <typename T>
struct B : A<T>
B(T val) : A<T>val
;
Then, I can call my expression template library as follows (with an overload for printing to std::cout
):
template <typename T, typename U>
std::ostream &operator<<(std::ostream &os, const mul<T, U> &m)
os << " unconstrained template n";
int main(int argc, char const *argv[])
B<double> a2;
B<double> b3;
std::cout << tran(a) * b << "n";
return 0;
This gives me the output :
called: mul<T, U> operator*(const T &one, const T &two)
unconstrained template
So far so good. Suppose now that I want a specialized treatment for 'transpose of a variable of type A<T>
times a variable of type A<T>
for some type T
', as I had in my main
. To this end, I will introduce
template <typename T>
T operator*(const transpose<A<T>> &one, const A<T> &two)
std::cout << " called: T operator*(const A<T> &one, const A<T> &two)n";
return one.t.elem * two.elem;
I run the same main
function as above, and I still get the same output as above (unconstrained template
). This is to be expected, since transpose<B<double>>
is a completely different type compared to transpose<A<double>>
, so overload resolution picks the unconstrained template version of operator*
.
(Of course, if I change my variable definitions in main
to A
instead of B
, ADL calls the specialized function and output is called: T operator*(const A<T> &one, const A<T> &two)
and 6
).
I recently learned about SFINAE, so I expected the following change to the more specific multiplication operator would cause overload resulution to select the specialized function:
template <typename T, typename V>
std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const transpose<V> &one,
const V &two)
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)n";
return one.t.elem * two.elem;
Even using the SFINAE'd operator*
I still get the unconstrained template
version. How come? What changes should I make to call the more specialized template function?
c++ sfinae generic-programming expression-templates
add a comment |
I have this minimal expression template library with a multiplication, i.e.
template <typename T, typename U>
struct mul
const T &v1;
const U &v2;
;
template <typename T, typename U>
mul<T, U> operator*(const T &one, const U &two)
std::cout << " called: mul<T, U> operator*(const T &one, const T &two)n";
return mul<T, U>one, two;
and transpose, i.e.
template <typename T>
struct transpose
const T &t;
;
template <typename T>
transpose<T> tran(const T &one)
return transpose<T>one;
I will introduce some types A
and B
, where the latter is a subclass of the former:
template <typename T>
struct A
T elem;
;
template <typename T>
struct B : A<T>
B(T val) : A<T>val
;
Then, I can call my expression template library as follows (with an overload for printing to std::cout
):
template <typename T, typename U>
std::ostream &operator<<(std::ostream &os, const mul<T, U> &m)
os << " unconstrained template n";
int main(int argc, char const *argv[])
B<double> a2;
B<double> b3;
std::cout << tran(a) * b << "n";
return 0;
This gives me the output :
called: mul<T, U> operator*(const T &one, const T &two)
unconstrained template
So far so good. Suppose now that I want a specialized treatment for 'transpose of a variable of type A<T>
times a variable of type A<T>
for some type T
', as I had in my main
. To this end, I will introduce
template <typename T>
T operator*(const transpose<A<T>> &one, const A<T> &two)
std::cout << " called: T operator*(const A<T> &one, const A<T> &two)n";
return one.t.elem * two.elem;
I run the same main
function as above, and I still get the same output as above (unconstrained template
). This is to be expected, since transpose<B<double>>
is a completely different type compared to transpose<A<double>>
, so overload resolution picks the unconstrained template version of operator*
.
(Of course, if I change my variable definitions in main
to A
instead of B
, ADL calls the specialized function and output is called: T operator*(const A<T> &one, const A<T> &two)
and 6
).
I recently learned about SFINAE, so I expected the following change to the more specific multiplication operator would cause overload resulution to select the specialized function:
template <typename T, typename V>
std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const transpose<V> &one,
const V &two)
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)n";
return one.t.elem * two.elem;
Even using the SFINAE'd operator*
I still get the unconstrained template
version. How come? What changes should I make to call the more specialized template function?
c++ sfinae generic-programming expression-templates
Maybe my understanding of what ADL is is incorrect, but what this has to do with ADL?
– Evg
May 29 at 12:38
I thought 'Overload Resolution' and ADL are the same. Apparently, they're not.
– Nibor
May 29 at 13:10
Overloading resolution is choosing between names found incl. those found by ADL.
– curiousguy
Jun 6 at 5:49
add a comment |
I have this minimal expression template library with a multiplication, i.e.
template <typename T, typename U>
struct mul
const T &v1;
const U &v2;
;
template <typename T, typename U>
mul<T, U> operator*(const T &one, const U &two)
std::cout << " called: mul<T, U> operator*(const T &one, const T &two)n";
return mul<T, U>one, two;
and transpose, i.e.
template <typename T>
struct transpose
const T &t;
;
template <typename T>
transpose<T> tran(const T &one)
return transpose<T>one;
I will introduce some types A
and B
, where the latter is a subclass of the former:
template <typename T>
struct A
T elem;
;
template <typename T>
struct B : A<T>
B(T val) : A<T>val
;
Then, I can call my expression template library as follows (with an overload for printing to std::cout
):
template <typename T, typename U>
std::ostream &operator<<(std::ostream &os, const mul<T, U> &m)
os << " unconstrained template n";
int main(int argc, char const *argv[])
B<double> a2;
B<double> b3;
std::cout << tran(a) * b << "n";
return 0;
This gives me the output :
called: mul<T, U> operator*(const T &one, const T &two)
unconstrained template
So far so good. Suppose now that I want a specialized treatment for 'transpose of a variable of type A<T>
times a variable of type A<T>
for some type T
', as I had in my main
. To this end, I will introduce
template <typename T>
T operator*(const transpose<A<T>> &one, const A<T> &two)
std::cout << " called: T operator*(const A<T> &one, const A<T> &two)n";
return one.t.elem * two.elem;
I run the same main
function as above, and I still get the same output as above (unconstrained template
). This is to be expected, since transpose<B<double>>
is a completely different type compared to transpose<A<double>>
, so overload resolution picks the unconstrained template version of operator*
.
(Of course, if I change my variable definitions in main
to A
instead of B
, ADL calls the specialized function and output is called: T operator*(const A<T> &one, const A<T> &two)
and 6
).
I recently learned about SFINAE, so I expected the following change to the more specific multiplication operator would cause overload resulution to select the specialized function:
template <typename T, typename V>
std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const transpose<V> &one,
const V &two)
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)n";
return one.t.elem * two.elem;
Even using the SFINAE'd operator*
I still get the unconstrained template
version. How come? What changes should I make to call the more specialized template function?
c++ sfinae generic-programming expression-templates
I have this minimal expression template library with a multiplication, i.e.
template <typename T, typename U>
struct mul
const T &v1;
const U &v2;
;
template <typename T, typename U>
mul<T, U> operator*(const T &one, const U &two)
std::cout << " called: mul<T, U> operator*(const T &one, const T &two)n";
return mul<T, U>one, two;
and transpose, i.e.
template <typename T>
struct transpose
const T &t;
;
template <typename T>
transpose<T> tran(const T &one)
return transpose<T>one;
I will introduce some types A
and B
, where the latter is a subclass of the former:
template <typename T>
struct A
T elem;
;
template <typename T>
struct B : A<T>
B(T val) : A<T>val
;
Then, I can call my expression template library as follows (with an overload for printing to std::cout
):
template <typename T, typename U>
std::ostream &operator<<(std::ostream &os, const mul<T, U> &m)
os << " unconstrained template n";
int main(int argc, char const *argv[])
B<double> a2;
B<double> b3;
std::cout << tran(a) * b << "n";
return 0;
This gives me the output :
called: mul<T, U> operator*(const T &one, const T &two)
unconstrained template
So far so good. Suppose now that I want a specialized treatment for 'transpose of a variable of type A<T>
times a variable of type A<T>
for some type T
', as I had in my main
. To this end, I will introduce
template <typename T>
T operator*(const transpose<A<T>> &one, const A<T> &two)
std::cout << " called: T operator*(const A<T> &one, const A<T> &two)n";
return one.t.elem * two.elem;
I run the same main
function as above, and I still get the same output as above (unconstrained template
). This is to be expected, since transpose<B<double>>
is a completely different type compared to transpose<A<double>>
, so overload resolution picks the unconstrained template version of operator*
.
(Of course, if I change my variable definitions in main
to A
instead of B
, ADL calls the specialized function and output is called: T operator*(const A<T> &one, const A<T> &two)
and 6
).
I recently learned about SFINAE, so I expected the following change to the more specific multiplication operator would cause overload resulution to select the specialized function:
template <typename T, typename V>
std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const transpose<V> &one,
const V &two)
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)n";
return one.t.elem * two.elem;
Even using the SFINAE'd operator*
I still get the unconstrained template
version. How come? What changes should I make to call the more specialized template function?
c++ sfinae generic-programming expression-templates
c++ sfinae generic-programming expression-templates
edited Jun 6 at 3:49
Ratan Uday Kumar
1,30421533
1,30421533
asked May 29 at 12:24
NiborNibor
754421
754421
Maybe my understanding of what ADL is is incorrect, but what this has to do with ADL?
– Evg
May 29 at 12:38
I thought 'Overload Resolution' and ADL are the same. Apparently, they're not.
– Nibor
May 29 at 13:10
Overloading resolution is choosing between names found incl. those found by ADL.
– curiousguy
Jun 6 at 5:49
add a comment |
Maybe my understanding of what ADL is is incorrect, but what this has to do with ADL?
– Evg
May 29 at 12:38
I thought 'Overload Resolution' and ADL are the same. Apparently, they're not.
– Nibor
May 29 at 13:10
Overloading resolution is choosing between names found incl. those found by ADL.
– curiousguy
Jun 6 at 5:49
Maybe my understanding of what ADL is is incorrect, but what this has to do with ADL?
– Evg
May 29 at 12:38
Maybe my understanding of what ADL is is incorrect, but what this has to do with ADL?
– Evg
May 29 at 12:38
I thought 'Overload Resolution' and ADL are the same. Apparently, they're not.
– Nibor
May 29 at 13:10
I thought 'Overload Resolution' and ADL are the same. Apparently, they're not.
– Nibor
May 29 at 13:10
Overloading resolution is choosing between names found incl. those found by ADL.
– curiousguy
Jun 6 at 5:49
Overloading resolution is choosing between names found incl. those found by ADL.
– curiousguy
Jun 6 at 5:49
add a comment |
1 Answer
1
active
oldest
votes
The problem is that in the SFINAE overload, T
is used in a non-deduced context. You're effectively asking the compiler: "Enable this if there exists a T
such that A<T>
is a base class of V
." Existential quantification is a good indicator that what you're asking for cannot be SFINAEd.
You can see this yourself if you disable the unconstrained template, as I did here. This forces the compiler to spell out why the other function is not admissible.
You can solve this by making T
available through your A
(and thus B
) classes, like this:
template <typename T>
struct A
using Type = T;
T elem;
;
template <typename V>
std::enable_if_t<std::is_base_of<A<typename V::Type>, V>::value, typename V::Type> operator*(const transpose<V> &one,
const V &two)
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)n";
return one.t.elem * two.elem;
[Live example]
In fact removing the sfinae, the superfluous template argument then uncommenting the uncontrainted one yield me the correct result.
– Guillaume Racicot
May 29 at 12:35
1
@GuillaumeRacicot Yes, that works in the reduced example posted. But note that the OP says that the constrained version should only be used whenV
is derived fromA<T>
for someA
. Removing the sfinae would make it apply to all transpose-nontranspose pairs.
– Angew
May 29 at 12:37
Reading this SFINAE it should only allowtypename V
to beB<T>
but given thatstd::is_base_of<Base, Derived>::value
yieldstrue
ifstd::is_same<Base, Derived>::value
it also allowsA<T>
. Shouldn't there be a check to disallow that, too? If I am understand OP's Intention correctly, that is.
– Stack Danny
May 29 at 14:00
@StackDanny I understood the OP's question as "how do I word SFINAE for a special case that involvesA<T>
or a type derived fromA<T>
?" That's how I read "Suppose now that I want a specialized treatment for 'transpose of a variable of typeA<T>
times a variable of typeA<T>
for some typeT
', as I had in mymain
." Note that it was aB<double>
in themain
, actually.
– Angew
May 29 at 14:02
@Angew I just find it weird because if you were to removestruct B
from the code the SFINAE (which strictly asks for astd::is_base_of
case) will still be called even though there is no inheritance whatsover going on. I just thoughts that's unintentional. I suppose this is to be blamed on the implementation ofstd::is_base_of
.
– Stack Danny
May 29 at 14:13
|
show 2 more comments
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%2f56360583%2fwhy-is-overload-resolution-favoring-unconstrained-template-function-over-a-more%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
The problem is that in the SFINAE overload, T
is used in a non-deduced context. You're effectively asking the compiler: "Enable this if there exists a T
such that A<T>
is a base class of V
." Existential quantification is a good indicator that what you're asking for cannot be SFINAEd.
You can see this yourself if you disable the unconstrained template, as I did here. This forces the compiler to spell out why the other function is not admissible.
You can solve this by making T
available through your A
(and thus B
) classes, like this:
template <typename T>
struct A
using Type = T;
T elem;
;
template <typename V>
std::enable_if_t<std::is_base_of<A<typename V::Type>, V>::value, typename V::Type> operator*(const transpose<V> &one,
const V &two)
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)n";
return one.t.elem * two.elem;
[Live example]
In fact removing the sfinae, the superfluous template argument then uncommenting the uncontrainted one yield me the correct result.
– Guillaume Racicot
May 29 at 12:35
1
@GuillaumeRacicot Yes, that works in the reduced example posted. But note that the OP says that the constrained version should only be used whenV
is derived fromA<T>
for someA
. Removing the sfinae would make it apply to all transpose-nontranspose pairs.
– Angew
May 29 at 12:37
Reading this SFINAE it should only allowtypename V
to beB<T>
but given thatstd::is_base_of<Base, Derived>::value
yieldstrue
ifstd::is_same<Base, Derived>::value
it also allowsA<T>
. Shouldn't there be a check to disallow that, too? If I am understand OP's Intention correctly, that is.
– Stack Danny
May 29 at 14:00
@StackDanny I understood the OP's question as "how do I word SFINAE for a special case that involvesA<T>
or a type derived fromA<T>
?" That's how I read "Suppose now that I want a specialized treatment for 'transpose of a variable of typeA<T>
times a variable of typeA<T>
for some typeT
', as I had in mymain
." Note that it was aB<double>
in themain
, actually.
– Angew
May 29 at 14:02
@Angew I just find it weird because if you were to removestruct B
from the code the SFINAE (which strictly asks for astd::is_base_of
case) will still be called even though there is no inheritance whatsover going on. I just thoughts that's unintentional. I suppose this is to be blamed on the implementation ofstd::is_base_of
.
– Stack Danny
May 29 at 14:13
|
show 2 more comments
The problem is that in the SFINAE overload, T
is used in a non-deduced context. You're effectively asking the compiler: "Enable this if there exists a T
such that A<T>
is a base class of V
." Existential quantification is a good indicator that what you're asking for cannot be SFINAEd.
You can see this yourself if you disable the unconstrained template, as I did here. This forces the compiler to spell out why the other function is not admissible.
You can solve this by making T
available through your A
(and thus B
) classes, like this:
template <typename T>
struct A
using Type = T;
T elem;
;
template <typename V>
std::enable_if_t<std::is_base_of<A<typename V::Type>, V>::value, typename V::Type> operator*(const transpose<V> &one,
const V &two)
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)n";
return one.t.elem * two.elem;
[Live example]
In fact removing the sfinae, the superfluous template argument then uncommenting the uncontrainted one yield me the correct result.
– Guillaume Racicot
May 29 at 12:35
1
@GuillaumeRacicot Yes, that works in the reduced example posted. But note that the OP says that the constrained version should only be used whenV
is derived fromA<T>
for someA
. Removing the sfinae would make it apply to all transpose-nontranspose pairs.
– Angew
May 29 at 12:37
Reading this SFINAE it should only allowtypename V
to beB<T>
but given thatstd::is_base_of<Base, Derived>::value
yieldstrue
ifstd::is_same<Base, Derived>::value
it also allowsA<T>
. Shouldn't there be a check to disallow that, too? If I am understand OP's Intention correctly, that is.
– Stack Danny
May 29 at 14:00
@StackDanny I understood the OP's question as "how do I word SFINAE for a special case that involvesA<T>
or a type derived fromA<T>
?" That's how I read "Suppose now that I want a specialized treatment for 'transpose of a variable of typeA<T>
times a variable of typeA<T>
for some typeT
', as I had in mymain
." Note that it was aB<double>
in themain
, actually.
– Angew
May 29 at 14:02
@Angew I just find it weird because if you were to removestruct B
from the code the SFINAE (which strictly asks for astd::is_base_of
case) will still be called even though there is no inheritance whatsover going on. I just thoughts that's unintentional. I suppose this is to be blamed on the implementation ofstd::is_base_of
.
– Stack Danny
May 29 at 14:13
|
show 2 more comments
The problem is that in the SFINAE overload, T
is used in a non-deduced context. You're effectively asking the compiler: "Enable this if there exists a T
such that A<T>
is a base class of V
." Existential quantification is a good indicator that what you're asking for cannot be SFINAEd.
You can see this yourself if you disable the unconstrained template, as I did here. This forces the compiler to spell out why the other function is not admissible.
You can solve this by making T
available through your A
(and thus B
) classes, like this:
template <typename T>
struct A
using Type = T;
T elem;
;
template <typename V>
std::enable_if_t<std::is_base_of<A<typename V::Type>, V>::value, typename V::Type> operator*(const transpose<V> &one,
const V &two)
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)n";
return one.t.elem * two.elem;
[Live example]
The problem is that in the SFINAE overload, T
is used in a non-deduced context. You're effectively asking the compiler: "Enable this if there exists a T
such that A<T>
is a base class of V
." Existential quantification is a good indicator that what you're asking for cannot be SFINAEd.
You can see this yourself if you disable the unconstrained template, as I did here. This forces the compiler to spell out why the other function is not admissible.
You can solve this by making T
available through your A
(and thus B
) classes, like this:
template <typename T>
struct A
using Type = T;
T elem;
;
template <typename V>
std::enable_if_t<std::is_base_of<A<typename V::Type>, V>::value, typename V::Type> operator*(const transpose<V> &one,
const V &two)
std::cout << " called: std::enable_if_t<std::is_base_of<A<T>, V>::value, T> operator*(const "
"transpose<V> &one, const V &two)n";
return one.t.elem * two.elem;
[Live example]
edited May 29 at 14:38
Nicol Bolas
298k35499673
298k35499673
answered May 29 at 12:31
AngewAngew
138k11270362
138k11270362
In fact removing the sfinae, the superfluous template argument then uncommenting the uncontrainted one yield me the correct result.
– Guillaume Racicot
May 29 at 12:35
1
@GuillaumeRacicot Yes, that works in the reduced example posted. But note that the OP says that the constrained version should only be used whenV
is derived fromA<T>
for someA
. Removing the sfinae would make it apply to all transpose-nontranspose pairs.
– Angew
May 29 at 12:37
Reading this SFINAE it should only allowtypename V
to beB<T>
but given thatstd::is_base_of<Base, Derived>::value
yieldstrue
ifstd::is_same<Base, Derived>::value
it also allowsA<T>
. Shouldn't there be a check to disallow that, too? If I am understand OP's Intention correctly, that is.
– Stack Danny
May 29 at 14:00
@StackDanny I understood the OP's question as "how do I word SFINAE for a special case that involvesA<T>
or a type derived fromA<T>
?" That's how I read "Suppose now that I want a specialized treatment for 'transpose of a variable of typeA<T>
times a variable of typeA<T>
for some typeT
', as I had in mymain
." Note that it was aB<double>
in themain
, actually.
– Angew
May 29 at 14:02
@Angew I just find it weird because if you were to removestruct B
from the code the SFINAE (which strictly asks for astd::is_base_of
case) will still be called even though there is no inheritance whatsover going on. I just thoughts that's unintentional. I suppose this is to be blamed on the implementation ofstd::is_base_of
.
– Stack Danny
May 29 at 14:13
|
show 2 more comments
In fact removing the sfinae, the superfluous template argument then uncommenting the uncontrainted one yield me the correct result.
– Guillaume Racicot
May 29 at 12:35
1
@GuillaumeRacicot Yes, that works in the reduced example posted. But note that the OP says that the constrained version should only be used whenV
is derived fromA<T>
for someA
. Removing the sfinae would make it apply to all transpose-nontranspose pairs.
– Angew
May 29 at 12:37
Reading this SFINAE it should only allowtypename V
to beB<T>
but given thatstd::is_base_of<Base, Derived>::value
yieldstrue
ifstd::is_same<Base, Derived>::value
it also allowsA<T>
. Shouldn't there be a check to disallow that, too? If I am understand OP's Intention correctly, that is.
– Stack Danny
May 29 at 14:00
@StackDanny I understood the OP's question as "how do I word SFINAE for a special case that involvesA<T>
or a type derived fromA<T>
?" That's how I read "Suppose now that I want a specialized treatment for 'transpose of a variable of typeA<T>
times a variable of typeA<T>
for some typeT
', as I had in mymain
." Note that it was aB<double>
in themain
, actually.
– Angew
May 29 at 14:02
@Angew I just find it weird because if you were to removestruct B
from the code the SFINAE (which strictly asks for astd::is_base_of
case) will still be called even though there is no inheritance whatsover going on. I just thoughts that's unintentional. I suppose this is to be blamed on the implementation ofstd::is_base_of
.
– Stack Danny
May 29 at 14:13
In fact removing the sfinae, the superfluous template argument then uncommenting the uncontrainted one yield me the correct result.
– Guillaume Racicot
May 29 at 12:35
In fact removing the sfinae, the superfluous template argument then uncommenting the uncontrainted one yield me the correct result.
– Guillaume Racicot
May 29 at 12:35
1
1
@GuillaumeRacicot Yes, that works in the reduced example posted. But note that the OP says that the constrained version should only be used when
V
is derived from A<T>
for some A
. Removing the sfinae would make it apply to all transpose-nontranspose pairs.– Angew
May 29 at 12:37
@GuillaumeRacicot Yes, that works in the reduced example posted. But note that the OP says that the constrained version should only be used when
V
is derived from A<T>
for some A
. Removing the sfinae would make it apply to all transpose-nontranspose pairs.– Angew
May 29 at 12:37
Reading this SFINAE it should only allow
typename V
to be B<T>
but given that std::is_base_of<Base, Derived>::value
yields true
if std::is_same<Base, Derived>::value
it also allows A<T>
. Shouldn't there be a check to disallow that, too? If I am understand OP's Intention correctly, that is.– Stack Danny
May 29 at 14:00
Reading this SFINAE it should only allow
typename V
to be B<T>
but given that std::is_base_of<Base, Derived>::value
yields true
if std::is_same<Base, Derived>::value
it also allows A<T>
. Shouldn't there be a check to disallow that, too? If I am understand OP's Intention correctly, that is.– Stack Danny
May 29 at 14:00
@StackDanny I understood the OP's question as "how do I word SFINAE for a special case that involves
A<T>
or a type derived from A<T>
?" That's how I read "Suppose now that I want a specialized treatment for 'transpose of a variable of type A<T>
times a variable of type A<T>
for some type T
', as I had in my main
." Note that it was a B<double>
in the main
, actually.– Angew
May 29 at 14:02
@StackDanny I understood the OP's question as "how do I word SFINAE for a special case that involves
A<T>
or a type derived from A<T>
?" That's how I read "Suppose now that I want a specialized treatment for 'transpose of a variable of type A<T>
times a variable of type A<T>
for some type T
', as I had in my main
." Note that it was a B<double>
in the main
, actually.– Angew
May 29 at 14:02
@Angew I just find it weird because if you were to remove
struct B
from the code the SFINAE (which strictly asks for a std::is_base_of
case) will still be called even though there is no inheritance whatsover going on. I just thoughts that's unintentional. I suppose this is to be blamed on the implementation of std::is_base_of
.– Stack Danny
May 29 at 14:13
@Angew I just find it weird because if you were to remove
struct B
from the code the SFINAE (which strictly asks for a std::is_base_of
case) will still be called even though there is no inheritance whatsover going on. I just thoughts that's unintentional. I suppose this is to be blamed on the implementation of std::is_base_of
.– Stack Danny
May 29 at 14:13
|
show 2 more comments
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%2f56360583%2fwhy-is-overload-resolution-favoring-unconstrained-template-function-over-a-more%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
Maybe my understanding of what ADL is is incorrect, but what this has to do with ADL?
– Evg
May 29 at 12:38
I thought 'Overload Resolution' and ADL are the same. Apparently, they're not.
– Nibor
May 29 at 13:10
Overloading resolution is choosing between names found incl. those found by ADL.
– curiousguy
Jun 6 at 5:49