C++ 用多态函数重写模板函数
如果我有C++ 用多态函数重写模板函数,c++,templates,polymorphism,template-specialization,C++,Templates,Polymorphism,Template Specialization,如果我有 template<class T> TalkyBuffer& operator<<(T const &object) { // Template ... } TalkyBuffer& operator<<(TalkySerialisable const &object); // Override 那么如果我表演 TalkyBuffer b; A test; b << test; talkybufferb
template<class T>
TalkyBuffer& operator<<(T const &object) { // Template
...
}
TalkyBuffer& operator<<(TalkySerialisable const &object); // Override
那么如果我表演
TalkyBuffer b;
A test;
b << test;
talkybufferb;
测试;
b定义函数TalkyBuffer&operator时,使用:
#包括
#包括
模板
typename boost::如果<
boost::是,
健谈者&
>::type operator我认为可以使用一个简单的基于函数的解决方案,重用函数重载进行派生
struct specialized {};
struct generic {};
template <class T>
TalkyBuffer& serialize(TalkyBuffer& buffer, T const& object, generic) {
...
}
generic dispatch(...) {} // always picked up last in overload resolution
template <class T>
TalkyBuffer& TalkyBuffer::operator<<(T const& object) { // Template
return serialize(*this, object, dispatch(object));
}
并创建一个派生的:
class A: public TalkySerialisable {};
那么,会发生什么
TalkyBuffer::Operatory他超载了,没有专业知识<代码>模板TalkyBuffer&Operator同意Luc。没有模板
我将覆盖。然而,您关于不需要强制转换的函数优先的观点确实很有趣,并解释了这种现象。我在想,在保留与通用的TalkyBuffer&operator@Elliot:嗯,确切地说,您不是在重写,而是在重载。重写是关于虚拟方法(动态多态性),而重载是关于拥有多个具有相同名称和不同参数的函数(这是另一种多态性,但发生在编译时)。@Luc:谢谢你的精确措辞。我更正了答案。我更喜欢一种侵入性较小的方式。容量检测或特征将允许基本模板不知道存在专门化的类型。@Matthieu:是的,基本模板必须知道存在重载的事实也让我感到困扰。“我会设法想出一个更好的解决办法。@Matthieu:问题是模板和继承经常一起工作得很糟糕。”。例如,如果我想使用一个trait类,我就不能为所有TalkySerializable
专门化它,因为trait
与专门化不匹配。这是一个我经常偶然发现的问题,并且总是用一些解决方法来解决,这些方法并不能完全让我满意,所以如果你对这个问题有一些见解,我很高兴听到他们@Matthieu:我添加了另一个使用标记调度来减少耦合的解决方案,请随意分享您对另一种方法的想法。我不知道有任何系统在没有为重载配置基本模板的情况下工作,我担心的是反向依赖:)b Nice,使用重载函数获取用于分派的标记要比类型traits好得多,因为它可以无缝地处理继承和隐式转换。@LucTouraille:我只希望能让它不那么笨拙,但是,如果我尝试将serialize
中的generic
参数直接替换为。
我会得到一个不明确的重载:x
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_base_of.hpp>
template<typename T>
typename boost::disable_if<
boost::is_base_of<TalkySerializable, T>,
TalkyBuffer &
>::type operator<<(T const & object) { // Template for non TalkySerializable
...
}
template <typename T>
typename boost::enable_if<
boost::is_base_of<TalkySerializable, T>,
TalkyBuffer &
>::type operator<<(T const & object); // Template overload for TalkySerializable
...
TalkyBuffer b;
A test;
b << test; // calls operator<< <A>(A const &), which instantiates
// the overload for TalkySerializable
b << 41; // calls operator<< <int>(int const &), which corresponds to
// the "default" overload
// TalkyBuffer.hpp
#include <iostream>
#include <boost/utility/enable_if.hpp>
#include <boost/mpl/has_xxx.hpp>
// defines a metafunction has_talky_buffer_tag<T> that allows us to know at
// compile-time if T has a member type named talky_buffer_tag
BOOST_MPL_HAS_XXX_TRAIT_DEF(talky_buffer_tag)
// tag for the default case
struct default_talky_buffer_tag {};
// trait class for obtaining the tag of a type
template <typename T, typename Enable = void >
struct talky_buffer_trait
{
typedef default_talky_buffer_tag type;
};
// specialization for types that provide a nested typedef
template <typename T>
struct talky_buffer_trait<T,
typename boost::enable_if<has_talky_buffer_tag<T> >::type>
{
typedef typename T::talky_buffer_tag type;
};
struct TalkyBuffer
{
// Insertion operator, which calls an implementation function that can
// be overloaded depending on the tag
template<typename T>
TalkyBuffer & operator<<(T const & object)
{
typename talky_buffer_trait<T>::type tag;
return insertionOperatorImpl(*this, object, tag);
}
};
// default implementation
template <typename T>
TalkyBuffer & insertionOperatorImpl(TalkyBuffer & buf, T const & object,
default_talky_buffer_tag)
{
std::cout << "default";
return buf;
}
//-------
// TalkySerializable.hpp
struct TalkySerializable
{
struct tag {};
typedef tag talky_buffer_tag;
};
// A inherits from the nested typedef
struct A : public TalkySerializable {};
// implementation for TalkySerializable objects
template <typename Serializable>
TalkyBuffer & insertionOperatorImpl(TalkyBuffer & buf, Serializable const & object,
TalkySerializable::tag)
{
std::cout << "specialized";
return buf;
}
//-------
int main()
{
TalkyBuffer b;
A test;
b << test; // outputs "specialized"
b << 41; // outputs "default"
}
struct specialized {};
struct generic {};
template <class T>
TalkyBuffer& serialize(TalkyBuffer& buffer, T const& object, generic) {
...
}
generic dispatch(...) {} // always picked up last in overload resolution
template <class T>
TalkyBuffer& TalkyBuffer::operator<<(T const& object) { // Template
return serialize(*this, object, dispatch(object));
}
TalkyBuffer& serialize(TalkyBuffer& buffer,
TalkySerialisable const& object,
specialized);
specialized dispatch(TalkySerialisable const&) {}
class A: public TalkySerialisable {};