1

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?

5
  • 2
    Can you add the complete compiler error message, including the extra lines (if any) about the function signatures the compiler considered? Commented Mar 20, 2018 at 1:29
  • Able to reproduce with gcc-6.4.0 and clang-6.0.0. clang's error message is more helpful than gcc's: template.cpp:31:17: error: member 'do_the_thing' found in multiple base classes of different types Commented Mar 20, 2018 at 1:40
  • @1201ProgramAlarm Added Commented Mar 20, 2018 at 1:43
  • What is it supposed to do if you pass a node<int, double> to another node<int, double> or similar scenarios? Commented Mar 20, 2018 at 1:57
  • @super To be honest, I haven't thought that far ahead. Commented Mar 20, 2018 at 2:01

1 Answer 1

2

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;
}
Sign up to request clarification or add additional context in comments.

4 Comments

I get that part. I've edited my question to include a request for a solution. I understand there may be a method to disambiguate the call with a using statement.
@JohnStritenberger i think you can go for DeanSeo solution. Though compiler will not be able to deduce proper type always, you can help him - live
To add my comment a bit here, as @RemyLebeau addressed, probably the OP will have to think about edge cases where a node with multiple template arguments takes another node with multiple template arguments and how they should be deduced to which type. Otherwise the OP will have to explictely declare the desired type.
@JohnStritenberger Please read the clause 3 here namespace.udecl. It is C++17, so it is not implemented yet in most compilers, but in future it can help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.