我试图将一组特定的函数放入一个单独的部分,但在使用 GCC 时遇到了麻烦。
namespace /* anonymous */ {
[[gnu::section(".mysection")]]
void regular_func() { }
template <class T>
[[gnu::section(".mysection")]]
void template_func() { }
} // namespace /* anonymous */
void (*ptr1)() = ®ular_func;
void (*ptr2)() = &template_func<int>;
有了 clang,regular_func
的符号和 template_func<int>
被放置在 .mysection
正如我所料。
$ clang++ -std=c++14 a.cpp -c && objdump -t a.o | grep -E "regular|template"
0000000000000000 l F .mysection 0000000000000006 _ZN12_GLOBAL__N_112regular_funcEv
0000000000000010 l F .mysection 0000000000000006 _ZN12_GLOBAL__N_113template_funcIiEEvv
但是对于 GCC,函数模板不放在 .mysection
中, 但在 .text.*
部分。
$ g++ -std=c++14 a.cpp -c && objdump -t a.o | grep -E "regular|template"
0000000000000000 l F .mysection 0000000000000007 _ZN12_GLOBAL__N_112regular_funcEv
0000000000000000 l F .text 0000000000000007 _ZN12_GLOBAL__N_113template_funcIiEEvv
我正在使用 clang-3.7.1 和 gcc-5.3.0。
如何强制 gcc 将模板实例化函数放在单独的部分中?
最佳答案
这可能有点小安慰,但如果您申请 section
,GCC 会同意的。
template <class T> void template_func()
的显式实例化属性,
对于每个 T
你想被实例化,例如
namespace /* anonymous */ {
[[gnu::section(".mysection")]]
void regular_func() { }
template <class T>
void template_func() { }
template [[gnu::section(".mysection")]] void template_func<int>();
} // namespace /* anonymous */
void (*ptr1)() = ®ular_func;
void (*ptr2)() = &template_func<int>;
然后:
$ g++ -std=c++14 a.cpp -c && objdump -C -t a.o | grep -E "regular|template"
0000000000000000 l F .mysection 0000000000000007 (anonymous namespace)::regular_func()
0000000000000007 l F .mysection 0000000000000007 void (anonymous namespace)::template_func<int>()
不幸的是 clang 拒绝:
template [[gnu::section(".mysection")]] void template_func<int>();
说:
template [[gnu::section(".mysection")]] void template_func<int>();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: an attribute list cannot appear here
因此每个编译器都必须有自己的方式,通过条件编译。
此外,此修复带来了额外的麻烦,您必须以某种方式确保
那template_func()
无法为任何 T
实例化你没有明确地
实例化。
您可以通过在函数模板的主体中静态断言来实现这一点
T
是类型之一 A,B,C...
你允许被实例化。那么如果它
曾经用 T
实例化过= D
, static_assert
会开火;你可以
添加 D
到列表中并为 D
添加显式实例化:
#include <type_traits>
template<typename T, typename First>
constexpr bool is_in()
{
return std::is_same<T,First>::value;
}
template<typename T, typename First, typename Second, typename ...Rest>
constexpr bool is_in()
{
return is_in<T,First>() || is_in<T,Second,Rest...>();
}
namespace /* anonymous */ {
[[gnu::section(".mysection")]]
void regular_func() { }
template <class T>
void template_func()
{
static_assert(is_in<T,int,float>(),"");
}
template [[gnu::section(".mysection")]] void template_func<int>();
template [[gnu::section(".mysection")]] void template_func<float>();
} // namespace /* anonymous */
void (*ptr1)() = ®ular_func;
void (*ptr2)() = &template_func<int>;
void (*ptr3)() = &template_func<float>;
void (*ptr4)() = &template_func<char>; // <-- static_assert fails
关于c++ - 功能模板的部分属性在 GCC 中被静默忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36279162/