3

注意:几个相关问题(例如,这个问题)最终被标记为与此问题重复。我知道这个特定问题,并按照相应答案中的解决方案进行操作。但是,不同的编译器会产生不同的行为,我不知道为什么。

我的库有一个类模板,我想为库中的某些模板参数提供实例,因为模板需要一些大量的编译时间。类模板可能如下所示 ( stack.hpp)

#ifndef MY_STACK
#define MY_STACK

template<class T>
class stack
{
public:
    stack();
};

#endif

它的实现驻留在相应的stack.tpp文件中

#ifndef MY_STACK_TPP
#define MY_STACK_TPP

#include <iostream>

template<class T>
stack<T>::stack()
{
    std::cout << "My stack constructor!" << std::endl;
}

#endif

由于我只想为某些模板参数提供支持,因此我stack.cpp创建了以下显式模板实例:

#include "stack.hpp"

template class stack<double>;
template class stack<char>;

#include "stack.tpp"

这可以使用 g++ 和 clang++ 编译,但生成的共享库的符号存在差异:

g++ -std=c++11 -c stack.cpp -o stack.so
nm -C stack.so | grep stack
0000000000000049 t _GLOBAL__sub_I_stack.cpp
0000000000000000 W stack<char>::stack()
0000000000000000 W stack<char>::stack()
0000000000000000 n stack<char>::stack()
0000000000000000 W stack<double>::stack()
0000000000000000 W stack<double>::stack()
0000000000000000 n stack<double>::stack()

对比

clang++-7 -std=c++11 -c stack.cpp -o stack.so
nm -C stack.so | grep stack
0000000000000050 t _GLOBAL__sub_I_stack.cpp

在我的应用程序中,使用 clang++ 找不到这样一个显式实例化类的构造函数,但使用 g++ 可以正常工作。我认为这个基本的 MWE 给出了原因。谁能告诉我如何使用 clang++ 获取类模板的构造函数符号?

4

1 回答 1

4

这个程序格式正确

引用[temp.explicit]/1 [强调我的]:

类、函数、变量或成员模板特化可以从其模板显式实例化。类模板成员函数、成员类或静态数据成员可以从与其类模板关联的成员定义显式实例化。[..]

并且,引用[temp.explicit]/9 [强调我的]:

命名类模板特化的显式实例化定义显式地实例化类模板特化,并且是仅在实例化点已定义的那些成员的显式实例化定义

因此,在 OPs 示例中,显式实例化定义stack<T>将不包括构造函数的显式实例化定义,因为显式实例化定义stack<T>放置通过.tpp包含提供构造函数定义之前。

引用[temp.point]/8 [强调我的]:

函数模板、成员函数模板或类模板的成员函数或静态数据成员的化可以在翻译单元内具有多个实例化点,并且除了上述实例化点之外,对于任何此类在翻译单元内有一个实例化点的特化,翻译单元的末端也被认为是一个实例化点。类模板的特化在翻译单元内最多有一个实例化点。任何模板的特化都可能在多个翻译单元中具有实例化点。如果根据单一定义规则,两个不同的实例化点赋予模板特化不同的含义,则程序是非良构的,不需要诊断。

因此,对于stack.cpp包含两个不同实例化点的情况,一个在 包含之前,一个在包含之后stack.tpp,则程序是非良构的。

但是,这里变得有点棘手,因为实例化点取决于类模板及其成员函数(/构造函数)的使用方式。正如上面引用的[temp.explicit]/9所涵盖的,显式实例化stack<T>不会导致其构造函数的显式实例化定义,我们将需要依赖[temp.point]获取详细信息,尤其是第 1 条, 2和4,关于它的使用上下文何时会导致包含之前的实例化点stack.tpp

这些案例中的任何一个都没有涵盖问题中的独立示例,因此我们的程序不是格式错误的。

GCC vs clang:看似不同的实例化行为?

谁能告诉我如何使用 clang++ 获取类模板的构造函数符号?

由于从未使用过构造函数,因此根本不应该(不需要)实例化它,但似乎(来自 OPs 符号转储)GCC 无论如何都会这样做(这不是非法的),而 clang 却没有。如果在包含之后track.tpp在哪里使用/引用构造函数,那么 GCC 和 clang 都会自然地实例化它(对于使用的特定专业化),因为它们随后需要这样做。

于 2020-02-14T12:28:26.800 回答