提供模板类的一种方法的定义

Posted

技术标签:

【中文标题】提供模板类的一种方法的定义【英文标题】:Provide definition of one method of a template class 【发布时间】:2015-01-15 20:07:32 【问题描述】:

是否可以提供模板类的方法之一的自定义定义。或者是全部还是全部,这意味着我必须按原样使用所有提供的定义,或者我必须创建/定义整个类的模板特化。

我正在编写一些测试代码以更好地理解编写自定义分配器。我想提供allocator::allocate() 的自定义定义。我是否必须转发声明分配器。还是我的 allocate() 原型错误?还是我必须为分配器提供模板特化,这样我才能提供自己的 allocate() 定义。

#include <memory>
#include <iostream>

template <>
std::allocator<int>::pointer 
std::allocator<int>::allocate(size_type n, std::allocator<void>::const_pointer hint)

    cout << "Doing an alloc for an int allocator" << endl;
    return nullptr;


int main()

    std::allocator<int> a1; // default allocator for ints
    int* a = a1.allocate(10); // space for 10 ints

得到以下错误:

$ g++ -std=c++11 ./t1.cc
./t1.cc:6:78: error: no member function 'allocate' declared in 'std::allocator<int>'

我正在使用 g++ 4.7.2。我查看了头文件“bits/allocator.h”(包含在定义类分配器的“内存”中。没有看到方法 allocate()。方法原型是否在基类之一中?

【问题讨论】:

你必须把它放到 std 命名空间中。 C++ 中没有模板函数特化。 (取而代之的是重载,在这种情况下对您没有帮助) @erenon 在 std 命名空间中放入“什么”? 【参考方案1】:

这是因为在 gcc 中,allocator 是这样定义的:

template<typename _Tp>
class allocator: public __glibcxx_base_allocator<_Tp>
 .. ;

allocate() 方法本身来自__glibcxx_base_allocator。现在,几行之后,这个基础就被删除了:

// Undefine.
#undef __glibcxx_base_allocator

作为阻止像你这样的人在代码中乱搞的气馁!

但是,让我以 DO NOT DO THIS EVER OMG 作为开头,为了胡闹,你可以发现 __glibcxx_base_allocator#defined 为 __gnu_cxx::new_allocator,并且您可以使用这些知识来专门化您的功能(请注意,它必须与原始模板位于相同的命名空间中 - 根据专业化规则):

namespace __gnu_cxx 

    template <>
    new_allocator<int>::pointer
    new_allocator<int>::allocate(
        new_allocator<int>::size_type n,
        std::allocator<void>::const_pointer hint)
    
        std::cout << "Doing an alloc for an int allocator" << std::endl;
        return nullptr;
    


我真的无法强调不要这样做。但是追踪起来很有趣。

【讨论】:

太棒了,非常感谢。是一次非常好的学习经历。我有个问题。当我使用 std::allocator 类型(在 main 中)时,类类型由编译器创建(包括 int 的 allocate() 版本)。我正在提供我自己的定义。为什么编译器不抱怨“相同”方法的重复定义。还是两者不一样?如果有,它们有何不同?【参考方案2】:

查看 MinGW g++4.9 附带的 libstdc++ 标头,allocate 成员函数的定义存在于标头 ext/new_allocator.h 中定义的类 new_allocator 中。 std::allocator 公开继承自 new_allocator

如果 libstdc++ 选择将 allocate 定义为 std::allocator 本身的成员函数,您的代码将被编译(它在 VS2013 上编译,因为 std::allocator 的实现确实定义了 allocate 成员函数),但是即便如此,这将是未定义的行为。

来自 N3337,§17.6.4.2.1/2 [namespace.std]

如果 C++ 程序声明了,则其行为未定义 — 标准库类模板的任何成员函数的显式特化,或...

如果您想自定义行为,您需要提供自己的分配器实现。

【讨论】:

只是好奇,再想一想,为什么代码会在你的环境下编译。编译器不应该抱怨 std::allocator::allocate() 的定义重复吗? @AhmedA 我不明白你的问题。如果我使用 g++,您的示例不会编译,如果我使用 MSVC,它会编译。但是没有重复定义的问题,因为这两种实现都没有提供 std::allocator&lt;int&gt; 的专门化 当你说代码在 VS2013 中编译时,因为 std::allocator 定义了 allocate()。在那种情况下,当我在 main 中使用类型 allocator 时,是否不会生成 std​​::allocator 的特化。而且我还在我的 cc 文件中提供了一个。这就是我所说的重复。对不起,如果我不清楚。 @AhmedA 不,我现在明白了。这不是成员函数的显式特化的工作方式。阅读this(搜索类模板的成员或成员模板)。您的显式特化将在您的示例中使用(如果您对其进行编译)。

以上是关于提供模板类的一种方法的定义的主要内容,如果未能解决你的问题,请参考以下文章

模板方法设计模式

模板方法(TemplateMethod)

面向对象:封装:构造函数;类的主方法;权限修饰符;对象的创建

java 定义类 如何写?

模板类 error LNK2019: 无法解析的外部符号

Java面向对象(15)_模板方法设计模式