代码之家  ›  专栏  ›  技术社区  ›  Wheezil

带模板参数的超载C++方法:如何为模板的子类实现这项工作?

  •  2
  • Wheezil  · 技术社区  · 8 年前

    我想为一个方法编写两个重载,一个带有作为特定模板实例的参数,另一个用于“其他所有内容”。当参数是模板专门化的实例时,这种方法有效,但对模板专门化的子类无效。例如:

    template <class T> class Ptr { public: T* ptr; };
    class C {};
    typedef Ptr<C> CPtr;
    class CPtrSub : public CPtr {};
    template <class T> void foo(const T& a, const T& b) {
        std::cout << "plain\n";
    }
    template <class T> void foo(const Ptr<T>& a, const Ptr<T>& b) {
        std::cout << "ptr\n";
    }
    int main() {
        CPtr p1, p2;
        CPtrSub p3, p4;
        foo(p1, p2);
        foo(p3, p4);
    }
    

    当我运行这个时,输出是:

    ptr
    plain
    

    除了模板本身之外,是否可以构建为模板的子类选择的重载?

    一些 “V”。

    template <typename T, typename = std::enable_if<!std::is_convertible<T, CPtr>::value >::type >
    void foo(const T& a, const T& b) {
        std::cout << "plain\n";
    }
    

    但试图走上“可转换为Ptr”的道路<V>对于某些V“产生编译错误(无法推断V):

    template <typename T, typename V, typename = std::enable_if<!std::is_convertible_v<T, Ptr<V> > >::value >
    void foo(const T& a, const T& b) {
        std::cout << "plain\n";
    }
    

    class PtrBase {};
    template <class T> class Ptr : public PtrBase { public: T * ptr; };
    class C {};
    typedef Ptr<C> CPtr;
    class CPtrSub : public CPtr {};
    template <typename T, typename = std::enable_if<!std::is_convertible<T, PtrBase>::value >::type >
    void foo(const T& a, const T& b) {
        std::cout << "plain\n";
    }
    template <class T> void foo(const Ptr<T>& a, const Ptr<T>& b) {
        std::cout << "ptr\n";
    }
    int main() {
        C c1, c2;
        CPtr p1, p2;
        CPtrSub p3, p4;
        foo(c1, c2);
        foo(p1, p2);
        foo(p3, p4);
    }
    

    生成输出

    plain
    ptr
    ptr
    

    所以彼得的回答是对的。如果有一个通用的答案不依赖于模板基类,那就更好了。

    最后的注释:这些元编程特性中的一些在C++ 11、C++ 17和C++ 20中可用。我将使用率降低到C++ 11的可用性。

    1 回复  |  直到 8 年前
        1
  •  1
  •   Peter Ruderman    8 年前

    我认为你必须在这里学习一些模板元编程。问题是,你的第一次超载是一个“更好的”匹配 Ptr<T> 子类,因为它不需要任何类型的转换。您可以通过从重载集中删除它来修复此问题。比如:

    template <class T> std::enable_if_t<!std::is_convertible_v<T, Ptr<T>>
    foo (const T& a, const T& b)
    {
        /* details */
    }