Интересный вопрос.Шаблоны и наследование не очень хорошо сочетаются, и, поскольку вы не можете исправить U
, это наверняка создаст интересную проблему.
Я предлагаю превзойти механизм удержания перегрузки:)
Простейшим способом было бы обеспечить перегрузку для каждого Derived
класса.Очевидно, что это непрактично.
Если мы не сможем использовать вспомогательный класс, для которого написан оператор, и смешать там typedefs, чтобы сделать его прозрачным для клиента.
template <typename T>
struct BaseT: Base
{
typedef T Tag;
};
template <typename T>
BaseT<T> operator*(U, BaseT<T> const&) { return BaseT<T>(); }
Это должно быть предпочтительным(как перегрузка) для любого BaseT<X>
, потому что он соответствует более точно, чем предложенная общая перегрузка.
struct DerivedTag {};
typedef BaseT<DerivedTag> Derived;
Tadaaaam:)
И поскольку BaseT
является классом, вы можетефактически специализируйте его на конкретных аргументах Tag, чтобы иметь именно те члены / другие функции, которые вы хотите, и он будет точно таким же для клиента.
Полный пример для Ideone на http://ideone.com/ZIudh, будем надеяться, что выне нажимайте на ошибку VS 2008;)
struct Base {};
template <typename T>
struct BaseT: Base
{
typedef T Tag;
};
struct DerivedTag {};
typedef BaseT<DerivedTag> Derived;
class Q {};
class U
{
public:
template< typename Y >
Q operator * (Y)
{
Q r;
return r;
}
};
Base operator * (U, const Base &)
{
Base r;
return r;
}
template <typename T>
BaseT<T> operator*(U, BaseT<T> const&) { return BaseT<T>(); }
int main(int argc, char **argv)
{
Base myBase;
U myU;
Base myOtherBase = myU * myBase;
Derived myDerived;
Derived myOtherDerived = myU * myDerived;
return 0;
}