Compiling this code :
#include <iostream>
template <int N>
struct TestClass {
template <int N2, typename std::enable_if<N2 == N, int>::type = 0>
void doAction() { std::cout << "TestClass::doAction<" << N << ">();\n"; }
};
struct HostClass : public TestClass<1>, public TestClass<2> {
};
int main(int argc, const char * argv[]) {
HostClass hostClass;
hostClass.doAction<1>();
hostClass.doAction<2>();
return 0;
}
leads to an ambiguous call error because doAction
is both in TestClass<1>
and TestClass<2>
parent classes.
main.cpp:33:15: Member 'doAction' found in multiple base classes of different types
But std::enable_if
would not disable this ambiguity ?
EDIT:
I think the real reason to this ambiguity is the same than in this question :
Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions?
The ambiguity can be resolved as shown in the answer with the using
keyword :
#include <iostream>
template <int N>
struct TestClass {
template <int N2, typename std::enable_if<N2 == N, int>::type = 0>
void doAction() { std::cout << "TestClass::doAction<" << N << ">();\n"; }
};
struct HostClass : public TestClass<1>, public TestClass<2> {
using TestClass<1>::doAction;
using TestClass<2>::doAction;
};
int main(int argc, const char * argv[]) {
HostClass hostClass;
hostClass.doAction<1>(); // OK, compile
hostClass.doAction<2>(); // OK, compile
//hostClass.doAction<3>(); // OK, doesn't compile : "candidate template ignored: disabled by 'enable_if' [with N2 = 3]"
return 0;
}
I don't know if it was what @skypjack answer meant but I let it anyway for its alternative method.
It would (let me say) drop one of the two functions after the substitution.
Anyway, first of all the compiler has to decide which function you intend to use when you invoke it as doAction<1>
, then it can go ahead with the substitution and eventually toss away the chosen function because of sfinae.
At the point of the invocation, both of them are valid candidates and the call is actually ambiguous.
Note that, as suggested by @Peregring-lk in the comments, TestClass<1>::doAction
and TestClass<2>::doAction
are two different functions placed in different namespaces, they are not overloads of the same function.
This is actually a common source of misunderstandings.
You can easily solve the issue as it follows:
#include <iostream>
template <int N>
struct TestClass {
void doAction() { std::cout << "TestClass::doAction<" << N << ">();\n"; }
};
struct HostClass : public TestClass<1>, public TestClass<2> {
template<int N>
void doAction() { return TestClass<N>::doAction(); }
};
int main(int argc, const char * argv[]) {
HostClass hostClass;
hostClass.doAction<1>();
hostClass.doAction<2>();
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With