[英]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:一些方法有助于您实现它:
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>;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.