2

I have a small program as follows:

#include <iostream>

template <typename T>
class X{
    public:
        bool something(){
            return true;
        }
};

class A: public X<A>{
};


class B: public A, public X<B>{
};


template <typename T>
bool use(T &t)
{
    return t.something();
}



int main()
{
    B b;
    std::cout << "use returned: " << use(b);
}

This will not compile because there is an ambiguity as to which of the two possible versions of something() should be selected:

In instantiation of 'bool use(T&) [with T = B]':
30:43:   required from here
22:20: error: request for member 'something' is ambiguous
6:14: note: candidates are: bool X<T>::something() [with T = B]
6:14: note:                 bool X<T>::something() [with T = A]
 In function 'bool use(T&) [with T = B]':
23:1: warning: control reaches end of non-void function [-Wreturn-type]

My question is, how can I resolve this ambiguity if the only place I can edit is the body of use()?

7
  • You could cast it to a X<T> or an A object. For example ((A)t).something() Commented Dec 10, 2017 at 3:19
  • I am a little unsure how that cast would look like. Just good old (mytype)? Commented Dec 10, 2017 at 3:23
  • Yes ((sometype)t).something() make sure you have the right () for order of operators. Commented Dec 10, 2017 at 3:26
  • Also let me know if this does not work (I tested it and it did) I have some other suggestions you could try. Commented Dec 10, 2017 at 3:37
  • Which version of something do you want called? Commented Dec 10, 2017 at 3:51

2 Answers 2

4

Yes. For example, you can qualify the call to something (godbolt):

template <typename T>
bool use(T &t)
{
    return t.A::something();
}
Sign up to request clarification or add additional context in comments.

Comments

1

You could add a specialization of the template “use” for the case where T derives from X and then casts to X inside.

template <typename T>
class X{
    public:
        bool something(){
            return true;
        }
};

class A: public X<A>{
};


class B: public A, public X<B>{
};

#
# If class derives from X<T> make sure to cast to X<T> before calling something
#
template<typename T>
typename std::enable_if<std::is_base_of<X<T>, T>::value, bool>::type use(T &t)
{
     return static_cast<X<T>&>(t).something();
}

#
# This gets run for everything that doesn't derive from X<T>
#
template<typename T>
typename std::enable_if<!std::is_base_of<X<T>, T>::value, bool>::type use(T &t)
{
     return t.something();
}

Have to check the syntax though, but this should make sure you get it for your special case while allowing anything with only one “something” call.

1 Comment

Updated code above to compile. Note that this allows you add specializations for any case where T is derived from multiple classes that have a "something" method. You would just add another template that specializes and casts.

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.