Reputation: 1264
I'm just starting my journey into more advanced template code. Consider the following...
template <typename T>
class node_base
{
public:
T member;
node_base() {}
void do_the_thing(node_base& other)
{
std::cout << other.member;
}
};
template <typename ...Args>
class node : public node_base<Args>...
{
public:
node() :node_base<Args>()...{}
};
int main()
{
node<int> int_node;
node<int, double> double_node;
int_node.do_the_thing(double_node);
double_node.do_the_thing(int_node); // ambiguous call
std::cin.ignore();
return 0;
}
Using Visual Studio 2017 15.4.5, I get the following...
error C2385: ambiguous access of 'do_the_thing' note: could be the 'do_the_thing' in base 'node_base' note: or could be the 'do_the_thing' in base 'node_base'
My understanding is that the compiler should be able to deduce the correct function based on the argument, in this case node<int>
. Why is this call considered ambiguous? What can I do to clarify the call while still maintaining this template pattern?
Upvotes: 1
Views: 91
Reputation: 19043
It's not about templates. You can reproduce it with the following:
struct A1 { void foo(); };
struct A2 { void foo(); };
struct B : A1, A2 {};
int main()
{
B b;
b.foo();
}
The relevant part of the Standard is
If the resulting set of declarations are not all from sub-objects of the same type, or the set has a nonstatic member and includes members from distinct sub-objects, there is an ambiguity and the program is ill-formed.
So, you have two subobjects of types node_base<int>
and node_base<double>
.
EDIT: To address changes in the question and as DeanSeo deleted his solution, i will post it here:
template <typename T>
class node_base
{
public:
T member = sizeof(T);
node_base() {}
void do_the_thing(node_base& other) {
std::cout << other.member << std::endl;
}
};
template <typename ...Args>
class node : public node_base<Args>...
{
public:
node() :node_base<Args>()...{}
template <class T>
void do_the_thing(node_base<T>& other) {
node_base<T>::do_the_thing(other);
}
};
int main()
{
node<int> int_node;
node<double, int> double_node;
int_node.do_the_thing<int>(double_node);
double_node.do_the_thing(int_node);
double_node.do_the_thing<double>(double_node);
double_node.do_the_thing<int>(double_node);
return 0;
}
Upvotes: 2