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 {};