使用模板模板参数进行模板定义的函数专用化
Function specialization in template definition with template template parameters
按照@Jonas在上一个问题中的建议,我定义了一个模板化类来保存任意包含对象(字符串、树等(的任意容器(向量、集合、映射等(。到目前为止,我的定义是这样的:
template <template <typename...> class Container, typename Containee = std::string, typename... extras>
class Lemario
{
public:
typedef typename Container<Containee, extras...>::iterator iterator;
typedef typename Container<Containee, extras...>::const_iterator const_iterator;
// Use 'Containee' here (if needed) like sizeof(Containee)
// or have another member variable like: Containee& my_ref.
Container<Containee, extras ...> mTheContainer;
int loadContainees(const char *filename) {
Containee w, line;
// do some stuff here
}
void appendContainee(const Containee &__x);
};
现在,我可以在内联(如 loadContainees(和模板定义外部定义方法。外面:
template <template <typename...> class Container, typename Containee, typename... extras>
Containee Lemario<Container, Containee, extras...>::transform_word(const Containee& word) const
{
Containee result;
return result;
}
目前为止,一切都好。
但是现在我想专门使用一种方法将Contaniee作为向量,映射,树附加到容器中,使用不同的方法。所以我尝试专门化 std::vector:
template <template <typename...> class Container, typename Containee, typename... extras>
void Lemario<std::vector, Word>::appendContainee(const Word & word)
{
mTheContainer.push_back(word);
}
但是我收到以下错误:
error: prototype for ‘void Lemario<std::vector, gong::Xtring>::appendContainee(const Word&)’ does not match any in class ‘Lemario<std::vector, gong::Xtring>’
除此之外,我只能专用于容器 std::vector ,但让包含对象不专用吗?
template <template <typename...> class Container, typename Containee, typename... extras>
void Lemario<std::vector, Containee>::appendContainee(const Containee & word)
{
mTheContainer.push_back(word);
}
问题是你的appendContainee
实现存在语法错误。将函数专用化为std::vector
和Word
的正确方法是这样编写:
template <>
void Lemario<std::vector, Word>::appendContainee(const Word & word)
{
mTheContainer.push_back(word);
}
演示
但是,此方法要求您每次都完全专用化函数,这意味着您必须同时指定容器和类型。可能您只想专注于std::vector
而不是Word
。
此问题通常使用标记调度模式来解决。在标记调度中,我们通过引入将通过重载正确选择的帮助程序方法,将专用化转变为重载问题。
我们在类中创建一个空的嵌套模板化结构:
private:
template<class...>
struct Lemario_tag{};
然后编写入口点方法将调用private
帮助程序方法:
template<class T>
void appendContaineeHelp(const Containee &x, Lemario_tag<T>)
{
static_assert(sizeof(T) == 0, "No specialization exists for this container");
}
void appendContaineeHelp(const Containee &x, Lemario_tag<std::vector<Containee, extras...>>)
{
mTheContainer.push_back(x);
}
第一个是 catch-all,如果您尝试使用非专用容器调用它,则会导致编译器错误。
第二个是专门用于std::vector
的。
我们这样定义我们的public
appendContainee
(简单的直通(:
void appendContainee(const Containee &x){
appendContaineeHelp(x, Lemario_tag<Container<Containee, extras...>>{});
}
我们可以像这样使用我们的容器:
Lemario<std::vector, std::string> vecString;
Lemario<std::vector, int> vecInt;
vecString.appendContainee("foo");
vecInt.appendContainee(1);
Lemario<std::set, int> set_int;
// set_int.appendContainee(1); // compiler error
更好的演示
您可以使用std::enable_if
(和SFINAE(来专门化该功能,这是一个在线示例。
template <template <typename...> class Container, typename Containee = std::string, typename... extras>
class Lemario
{
public:
typedef typename Container<Containee, extras...>::iterator iterator;
typedef typename Container<Containee, extras...>::const_iterator const_iterator;
// Use 'Containee' here (if needed) like sizeof(Containee)
// or have another member variable like: Containee& my_ref.
Container<Containee, extras ...> mTheContainer;
int loadContainees(const char *filename) {
Containee w, line;
// do some stuff here
return 0; // To make the compiler happy
}
template <typename Containee2> // For SFINAE to work
typename std::enable_if<std::is_same<Container<Containee2, extras...>, std::vector<Containee2, extras...>>::value>::type
appendContainee(const Containee2 & word)
{
mTheContainer.push_back(word);
}
template <typename Containee2> // For SFINAE to work
typename std::enable_if<std::is_same<Container<Containee2, extras...>, std::deque<Containee2, extras...>>::value>::type
appendContainee(const Containee2 & word)
{
mTheContainer.push_back(word);
}
};
例
int main()
{
Lemario<std::vector, int> foo;
std::cout << foo.mTheContainer.size() << std::endl;
foo.appendContainee(1);
std::cout << foo.mTheContainer.size() << std::endl;
Lemario<std::deque, int> bar;
std::cout << bar.mTheContainer.size() << std::endl;
bar.appendContainee(1);
std::cout << bar.mTheContainer.size() << std::endl;
}
相关文章:
- 字符串化递归的"std::vector<std::vector<...>>"而不使用部分模板函数专用化
- 使用 C++20 概念模板函数专用化时的依赖项
- 将 c++ 类成员函数专用于模板类
- 使用模板模板参数进行模板定义的函数专用化
- 返回值的简单模板类成员函数专用化
- 已专用类的成员函数专用化
- 部分模板函数专用化enable_if:默认实现
- 使用数组参数进行函数专用化
- 模板函数专用化的内部编译器错误
- 在子类中定义可变参数函数专用化
- 使用模板的构造函数专用化
- 模板函数专用化Enable_if
- 如何将模板构造函数专用化移动到 cpp 文件
- 模板类模板构造函数专用化
- 模板类是否可以用作模板函数专用化的参数
- 未调用数组的函数专用化
- 如何将模板成员函数专用化为另一个模板类
- 模板类的模板函数专用化
- 参数值的自动模板函数专用化
- 如何在类中使用成员函数专用化