【问题标题】:Function Template Specialization Syntax aggregating templated types聚合模板类型的函数模板专业化语法
【发布时间】:2018-01-23 20:57:04
【问题描述】:

关于函数模板的特化,我想要一些语法方面的帮助。下面是一个简化的场景:

基本标题:

template <typename T>
void Foo(T* t) { TRACE("Default Foo impl"); }  // <-- default implementation

template <typename T>
struct Base
{
    explicit Base()
    {
        static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
        Foo(static_cast<T*>(this));
    }
};

Derived_X 标头:

struct Derived_X : public Base<Derived_X>
{
    explicit Derived_X() : Base<Derived_X> { } { }
};

// no specialization will be implemented --> using default

Derived_Y 标头:

struct Derived_Y : public Base<Derived_Y>
{
    explicit Derived_Y() : Base<Derived_Y> { } { }
};

template <>  // Foo specialization for Derived_Y
void Foo<Derived_Y>(Derived_Y* t)
{
    Foo(static_cast<Base<Derived_Y>*>(t));  // <-- call default impl
    TRACE("Derived_Y Foo impl");
}

Derived_Z 标头:

template <typename T>
struct Derived_Z : public Base<T>
{
    explicit Derived_Z() : Base<T> { }
    {
        static_assert(std::is_base_of<Derived_Z, T>::value, "T must derive from Derived_Z");
    }
};

/*  What does this specialization look like?
template <typename T>
void Foo<Derived_Z<T>>(Derived_Z<T>* t)
{
    Foo(static_cast<Base<T>*>(t));  // <-- call default impl
    TRACE("Derived_Z<T> Foo impl");
}
// */

MostDerived 标头:

struct MostDerived : public Derived_Z<MostDerived>
{
    explicit MostDerived() : Derived_Z<MostDerived> { } { }
};

template <>
void Foo<MostDerived>(MostDerived* t)
{
    Foo(static_cast<Derived_Z<MostDerived>*>(t));  // <-- call Derived_Z impl
    TRACE("MostDerived Foo impl");
}

用法:

int main()
{
    Derived_X dx { };   // <-- "Default Foo impl"
    Derived_Y dy { };   // <-- "Default Foo impl" && "Derived_Y Foo impl"
    MostDerived md { }; // <-- "Default Foo impl" && "MostDerived Foo impl"
}

我无法确定如何将Foo 专门用于Derived_Z。任何帮助将不胜感激!

【问题讨论】:

    标签: c++ c++11 templates template-specialization function-templates


    【解决方案1】:

    专门化功能模板通常被认为是一种糟糕的形式。您将无法部分专业化(正如您已经注意到的),并且在重载解决方案中不会考虑它们。相反,只需创建重载,然后让重载决议处理其余的事情。

    // no template at all for Derived_Y
    void Foo(Derived_Y* t)
    {
        Foo(static_cast<Base<Derived_Y>*>(t));  // <-- call default impl
        TRACE("Derived_Y Foo impl");
    }
    
    // a regular template (no specialization) for Derived_Z<T>
    template <typename T>
    void Foo(Derived_Z<T>* t)
    {
        Foo(static_cast<Base<T>*>(t));  // <-- call default impl
        TRACE("Derived_Z<T> Foo impl");
    }
    
    // again, no template for MostDerived
    void Foo(MostDerived* t)
    {
        Foo(static_cast<Derived_Z<MostDerived>*>(t));  // <-- call Derived_Z impl
        TRACE("MostDerived Foo impl");
    }
    

    现在,您可能需要考虑将基本实现更改为仅接受 Base&lt;T&gt;* 而不是 T*。假设您有派生自Derived_YDerived_Y2,但您尚未为Foo(Derived_Y2*) 定义重载。使用指向Derived_Y2 的指针调用Foo() 然后将转到Foo(T*),其中T 被推断为Derived_Y2,因为这比Foo(Derived_Y*) 更好匹配

    struct Derived_Y2 : Derived_T { };
    Derived_Y2 y2; // "Default Foo impl"
    

    通过将基本实现更改为:

    template<class T>
    void Foo(Base<T>*) { TRACE("Default Foo impl"); }
    

    Foo(Derived_Y*) 现在在将指针指向 Derived_Y2 时会更好地匹配,因为正如他们所说,它更专业

    【讨论】:

    • 效果很好。这么简单——我有点尴尬。作为一个额外的好处,这些函数可以在不同的命名空间中定义为友元函数,甚至可以在目标结构本身中定义。谢谢!
    【解决方案2】:

    我无法确定如何将 Foo 专门化为 Derived_Z。

    这是因为您不能对模板函数进行部分特化。

    但您可以部分专门化 class/struct

    所以我建议使用助手struct

    template <typename T>
    struct bar
     {
       static void func (T *)
        { std::cout << "default bar" << std::endl; }
     };
    
    template <>
    struct bar<Derived_Y>
     {
       static void func (Derived_Y *)
        { std::cout << "Derived_Y bar" << std::endl; }
     };
    
    template <typename T>
    struct bar<Derived_Z<T>>
     {
       static void func (Derived_Z<T> *)
        { std::cout << "Derived_Z<T> bar" << std::endl; }
     };
    

    Foo() 就变成了

    template <typename T>
    void Foo (T * t)
     { bar<T>::func(t); }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多