John Stritenberger
John Stritenberger

Reputation: 1264

Ambiguous variadic class member access

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

Answers (1)

Yola
Yola

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

Related Questions