Why the ambiguity?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <fstream>

class Item {
	public:
        virtual Item* createFrom (std::istream&) const = 0;
};

template <typename Derived>
class ItemCRTP : virtual public Item {};

class Ball : virtual public Item {
	public:
		virtual Ball* createFrom (std::istream&) const = 0;
		void load (std::istream&) {}
};

template <typename Derived>
class BallCRTP : virtual public Ball {
	protected:
		virtual Ball* createFrom (std::istream& is) const override {Derived* derived = new Derived;  derived->load(is);  return derived;}
};

class SportBall : virtual public Ball {};

class SoccerBall : public SportBall, public ItemCRTP<SoccerBall>, public BallCRTP<SoccerBall> {};

template <typename T>
class SpecialBall : public T, public ItemCRTP<SpecialBall<T>>, public BallCRTP<SpecialBall<T>> {
	virtual Ball* createFrom (std::istream& is) const override {return BallCRTP<SpecialBall<T>>::createFrom(is);}
};

int main() {
        SoccerBall a
	SpecialBall<SoccerBall> b;
}

// Visual Studio 2013:  error C2250: 'SpecialBall<SoccerBall>' : ambiguous inheritance of 'Ball *Item::createFrom(std::istream &) const' Line 30 


The code runs fine with GCC though. Is there undefined behaviour somewhere? What can I add here so that it compiles on Visual Studio 2013?
Last edited on
It is a known bug in Visual Studio. It does not vork properly when both covarint return types and virtual inheritance are used in same class.

https://connect.microsoft.com/VisualStudio/feedback/details/590625/visual-c-incorrectly-reports-ambiguity-when-covariance-is-used-with-virtual-inheritance
Last edited on
Wow! And Microsoft states that the bug is not fixable either! Then perhaps this is an acceptable workaround? It compiles on Visual Studio now at least. I need the function in the base class and in immediate child classes like Ball.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <fstream>

class Item {
	public:
        virtual Item* create (std::istream&) const = 0;  // ***Changed name
};

template <typename Derived>
class ItemCRTP : virtual public Item {
};

class Ball : virtual public Item {
	public:
		virtual Ball* createFrom (std::istream&) const = 0;
		void load (std::istream&) {}
	private:
		virtual Ball* create (std::istream& is) const override {return createFrom(is);}  // ***Added
};

template <typename Derived>
class BallCRTP : virtual public Ball {
	protected:
		virtual Ball* createFrom (std::istream& is) const override {Derived* derived = new Derived;  derived->load(is);  return derived;}
};

class SportBall : virtual public Ball {};

class SoccerBall : public SportBall, public ItemCRTP<SoccerBall>, public BallCRTP<SoccerBall> {};

template <typename T>
class SpecialBall : public T, public ItemCRTP<SpecialBall<T>>, public BallCRTP<SpecialBall<T>> {
	virtual Ball* createFrom (std::istream& is) const override {return BallCRTP<SpecialBall<T>>::createFrom(is);}
};

int main() {
	SoccerBall a;
	SpecialBall<SoccerBall> b;
}
Last edited on
Actually it is enough to get rid of covariance. Make all createFrom functions return Item* pointer.
Yes, for this sample. I need covariant return types in my actual program. I guess I just have to deal with the inconvenience then.
Topic archived. No new replies allowed.