Я пробовал код, представленный Шон Ройент в его разговоре на GoingNative 2013 - "Наследование - это базовый класс зла" . (код от последнего слайд доступен в https://gist.github.com/berkus/7041546
Я попытался достичь одной и той же цели самостоятельно, но я не могу понять, почему приведенный ниже код не будет действовать, как я ожидаю.
#include <boost/smart_ptr.hpp>
#include <iostream>
#include <ostream>
template <typename T>
void draw(const T& t, std::ostream& out)
{
std::cout << "Template version" << '\n';
out << t << '\n';
}
class object_t
{
public:
template <typename T>
explicit object_t (T rhs) : self(new model<T>(rhs)) {};
friend void draw(const object_t& obj, std::ostream& out)
{
obj.self->draw(out);
}
private:
struct concept_t
{
virtual ~concept_t() {};
virtual void draw(std::ostream&) const = 0;
};
template <typename T>
struct model : concept_t
{
model(T rhs) : data(rhs) {};
void draw(std::ostream& out) const
{
::draw(data, out);
}
T data;
};
boost::scoped_ptr<concept_t> self;
};
class MyClass {};
void draw(const MyClass&, std::ostream& out)
{
std::cout << "MyClass version" << '\n';
out << "MyClass" << '\n';
}
int main()
{
object_t first(1);
draw(first, std::cout);
const object_t second((MyClass()));
draw(second, std::cout);
return 0;
}
Эта версия обрабатывает печать int
отлично, но не выполняет компиляцию во втором случае, поскольку компилятор не знает, как использовать MyClass
с operator<<
. Я не могу понять, почему компилятор не будет выбирать вторую перегрузку, предоставленную специально для MyClass
. Код компилируется и отлично работает, если я изменяю имя метода model:: draw() и удаляю из его тела спецификатор пространства имен ::
, или если я изменяю глобальную функцию рисования MyClass на полную специализацию шаблона.
Сообщение об ошибке, которое я получаю, приведено ниже, после чего это куча candidate function not viable...
t76_stack_friend_fcn_visibility.cpp:9:9: error: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'const MyClass')
out << t << '\n';
~~~ ^ ~
t76_stack_friend_fcn_visibility.cpp:36:15: note: in instantiation of function template specialization 'draw<MyClass>' requested here
::draw(data, out);
^
t76_stack_friend_fcn_visibility.cpp:33:9: note: in instantiation of member function 'object_t::model<MyClass>::draw' requested here
model(T rhs) : data(rhs) {};
^
t76_stack_friend_fcn_visibility.cpp:16:42: note: in instantiation of member function 'object_t::model<MyClass>::model' requested here
explicit object_t (T rhs) : self(new model<T>(rhs)) {};
^
t76_stack_friend_fcn_visibility.cpp:58:20: note: in instantiation of function template specialization 'object_t::object_t<MyClass>' requested here
const object_t second((MyClass()));
^
Почему шаблонная версия функции глобального шаблона дроби выбрана из-за перегрузки функции MyClass? Это потому, что ссылка на шаблон является жадной? Как исправить эту проблему?