使用 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 都会自然地实例化它(对于所使用的特定专业化),因为他们需要这样做。
注意:几个相关问题(例如,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 都会自然地实例化它(对于所使用的特定专业化),因为他们需要这样做。