简体   繁体   English

只有一个参数的模板特化

[英]Template specialization with only one parameter

If you have a class template such as this:如果您有这样的类模板:

    template <typename T, unsigned CAPACITY>
    class Collection
    {
        T m_array[CAPACITY]{};
        T m_dummy{};
        unsigned m_size{};
    }
    public:
        void display(std::ostream& ostr = std::cout) const 
        {
            ostr << "----------------------" << std::endl;
            ostr << "| Collection Content |" << std::endl;
            ostr << "----------------------" << std::endl;
        }

And I wanted to create specialization depending on the type used, but not the CAPACITY, is this possible?而且我想根据使用的类型而不是容量来创建专业化,这可能吗?

I have this, which works:我有这个,它有效:

    void Collection<Pair, 50u>::display(std::ostream& ostr) const
    {
        ostr << "----------------------" << std::endl;
        ostr << "| This is a Pair |" << std::endl;
        ostr << "----------------------" << std::endl;
    }

When it is called as: Collection<Pair, 50> colDictionary;当它被称为: Collection<Pair, 50> colDictionary;

But this only works if the type is Pair, as well as the exact CAPACITY is 50.但这仅在类型为 Pair 并且确切的 CAPACITY 为 50 时才有效。

This is what I had in mind, allowing for type to be Pair and CAPACITY to be anything:这就是我的想法,允许 type 为 Pair 和 CAPACITY 为任何东西:

    void Collection<Pair>::display(std::ostream& ostr) const
    {
        ostr << "----------------------" << std::endl;
        ostr << "| This is a Pair |" << std::endl;
        ostr << "----------------------" << std::endl;
    }

But this causes a "too few arguments for class template" error.但这会导致“类模板的参数太少”错误。

Any way to do this without changing the actual class template itself?有什么方法可以在不更改实际类模板本身的情况下做到这一点?

It's called a partial template specialization :它被称为部分模板专业化

template <class T, unsigned Capacity>
struct Collection {

};

template <unsigned Capacity>
struct Collection<Pair, Capacity> {
  // Specialize
};

One thing to note is that you cannot partially specialize a single function.需要注意的一点是,您不能部分专门化单个函数。 You have to specialize the whole class template, which is irritating if the class template is long.你必须专门化整个类模板,如果类模板很长,这很烦人。 Another quick-and-dirty way of doing this if you want to specialize a single function would be to just use a "compile-time if":如果您想专门化单个函数,另一种快速而肮脏的方法是仅使用“编译时 if”:

#include <type_traits>

template <class T, unsigned Capacity>
struct Collection {
  void display() const {
    if constexpr (std::is_same_v<T, Pair>) {
      // pair implementation
    } else {
      // general implementation
    }
  }
};

Or, as a more clean solution, try moving the whole thing out of the class and add a simple overload:或者,作为一个更干净的解决方案,尝试将整个内容移出类并添加一个简单的重载:

// Free-standing overloads:

template <class T, unsigned Capacity>
void diplay(Collection<T, Capacity> const& c) { /* ... */ }

template <unsigned Capacity>
void display(Collection<Pair, Capacity> const& c) { /* ... */ }


// The member function delegates the work to
// the overloaded functions. No template specialization
// is involved:

template <class T, unsigned Capacity>
struct Capacity {
  void display() const {
    display(*this); // calls the correct overload.
  }
};

It seems difficult to do a partial specification.做一个部分规范似乎很困难。

Some ways are helpful for you to achieve it:一些方法有助于您实现它:

  1. Define a specification class for this type situation.为这种类型的情况定义一个规范类。
  2. If you just only desire to custom this behavior(but not too much and it's limited), you can use if-constexpr branches.如果您只希望自定义此行为(但不是太多且受到限制),您可以使用 if-constexpr 分支。
  3. If you want to avoid a class-partial-template (because it's a burden to rewrite all codes), then use a global function template is helpful.如果您想避免使用类部分模板(因为重写所有代码是一种负担),那么使用全局函数模板会很有帮助。

Some suggested codes are given:给出了一些建议的代码:

#include <iostream> 

template <typename T, unsigned capacity> 
class Collection {
    public: 
    void display(std::ostream &ostr = std::cout) const; 
}; 

template <typename T, unsigned c> 
void Collection<T, c>::display(std::ostream &ostr) const {
    if constexpr (c == 50u) {
        ostr << "Specification! \n"; 
    } else {
        ostr << "Normal Realization. \n"; 
    }
}

int main() {
    Collection<int, 50> c; 
    c.display(); 
}

If you need to specialize a certain member function, you can use the Curiously Recurring Template Pattern (or CRTP for short).如果需要专门化某个成员函数,可以使用Curiously Recurring Template Pattern (或简称 CRTP)。 You'd then create a base class and a specialization of that base class.然后,您将创建一个基类和该基类的特化。 Both contain only the specific member function that you want to specialize.两者都只包含您想要专门化的特定成员函数。

template <class T, class CRTP, unsigned Capacity>
struct display_impl {
    void display() const {
        auto& This = static_cast<const CRTP&>(*this);
        // Use `This` to access members of Collection
    }
};

template <class CRTP, unsigned Capacity>
struct display_impl<Pair, CRTP, Capacity> {
    void display() const {
        auto& This = static_cast<const CRTP&>(*this);
        // Use `This` to access members of Collection
    }
};

Collection will now inherit from display_impl and supply itself as a template parameter: Collection现在将从display_impl继承作为模板参数提供自己:

template <class T, unsigned Capacity>
struct Collection : display_impl<T, Collection<T, Capacity>, Capacity> {
    friend struct display_impl<T, Collection<T, Capacity>, Capacity>;
};

Demo演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM