使用 clang 显式 C++ 模板实例化

Explicit C++ template instantiation with clang

注意:几个相关问题(例如,this one) ended up being marked as duplicates of this question。我知道这个特定问题并遵循相应答案中的解决方案。但是,不同的编译器会产生不同的行为,我不知道为什么。

我的库有一个 class 模板,我想为库中的某些模板参数提供实例,因为该模板需要大量编译时间。 class 模板可能如下所示 (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++ 找不到这样一个显式实例化 class 的构造函数,但它在 g++ 中工作正常。我认为这个基本的 MWE 给出了原因。谁能告诉我如何使用 clang++ 为我的 class 模板获取构造函数符号?

这个程序格式正确

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

A class, function, variable, or member template specialization can be explicitly instantiated from its template. A member function, member class or static data member of a class template can be explicitly instantiated from the member definition associated with its class template. [..]

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

An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.

因此,在OPs示例中,stack<T>的显式实例化定义将不包括构造函数的显式实例化定义,因为stack<T>的显式实例化定义被放置在before 通过 .tpp include.

提供其构造函数的定义

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

A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above, for any such specialization that has a point of instantiation within the translation unit, the end of the translation unit is also considered a point of instantiation. A specialization for a class template has at most one point of instantiation within a translation unit. A specialization for any template may have points of instantiation in multiple translation units. If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.

因此,对于stack.cpp包含两个不同实例化点的情况,其中一个在包含stack.tpp之前,一个在包含stack.tpp之后,则程序格式错误。

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

问题中的独立示例未包含在任何这些案例中,因此我们的程序不是格式错误的。

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

Can anyone tell me how I can get the constructor symbols for my class template using clang++?

由于从未使用过构造函数,因此根本不应该(需要)实例化它,但似乎(从 OP 符号转储)GCC 无论如何都会这样做(这不是非法的)而 clang 不会.如果 use/refer 到构造函数 包含 track.tpp 之后,GCC 和 clang 都会自然地实例化它(对于所使用的特定专业化),因为他们需要这样做。