函数模板的部分属性在 GCC 中被静默忽略
Posted
技术标签:
【中文标题】函数模板的部分属性在 GCC 中被静默忽略【英文标题】:section attribute of a function template is silently ignored in GCC 【发布时间】:2016-03-29 08:30:05 【问题描述】:我正在尝试将一组特定的函数放在一个单独的部分中,但在使用 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 将模板实例化的函数放在单独的部分?
【问题讨论】:
提交了一个错误:gcc.gnu.org/bugzilla/show_bug.cgi?id=70435 【参考方案1】:这可能是一个小小的安慰,但如果您申请 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
【讨论】:
有趣的是,该属性可以用于显式实例化,但不幸的是,这不是我的选择。我在示例中将参数简化为单个类型 T 但它实际上是可变参数,因此我无法手动实例化所有可能的组合。【参考方案2】:不是最优雅的做事方式,但您可以进行一些名称修改并修改链接器脚本以获得所需的行为
#define TEMPLATE_SECTION(name, section) name##_##section##_
#define template_func TEMPLATE_SECTION(template_func, mysection)
template<class T>
void template_func()
void regular_func()
int main()
regular_func(); //placed in ".text"
template_func<int>(); //placed in ".mysection"
template_func<float>(); //placed in ".mysection"
return 0;
在链接描述文件中
SECTIONS
.mysection :
*(*_mysection_*)
.text :
*(.text .text.*)
【讨论】:
以上是关于函数模板的部分属性在 GCC 中被静默忽略的主要内容,如果未能解决你的问题,请参考以下文章