在GCC中静默忽略函数模板的section属性

Inb*_*ong 5 c++ attributes gcc c++11

我试图将一组特定的功能放入一个单独的部分,并且在使用GCC时遇到了麻烦.

namespace /* anonymous */ {
  [[gnu::section(".mysection")]]
  void regular_func() { }

  template <class T>
  [[gnu::section(".mysection")]]
  void template_func() { }
} // namespace /* anonymous */

void (*ptr1)() = &regular_func;
void (*ptr2)() = &template_func<int>;
Run Code Online (Sandbox Code Playgroud)

铿锵,两者的符号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
Run Code Online (Sandbox Code Playgroud)

但是对于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
Run Code Online (Sandbox Code Playgroud)

我正在使用clang-3.7.1和gcc-5.3.0.

如何强制gcc将模板实例化的函数放在一个单独的部分?

Mik*_*han 3

这可能有点安慰,但如果您将section 属性应用于 的显式实例化template <class T> void template_func(),对于T您想要实例化的每个实例,GCC 会强制要求,例如

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)() = &regular_func;
void (*ptr2)() = &template_func<int>;
Run Code Online (Sandbox Code Playgroud)

然后:

$ 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>()
Run Code Online (Sandbox Code Playgroud)

不幸的是clang拒绝了:

template [[gnu::section(".mysection")]] void template_func<int>();
Run Code Online (Sandbox Code Playgroud)

说:

template [[gnu::section(".mysection")]] void template_func<int>();
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: an attribute list cannot appear here
Run Code Online (Sandbox Code Playgroud)

所以每个编译器必须有自己的方式,通过条件编译。

此外,此修复带来了额外的麻烦,您必须以某种方式确保template_func()无法为T您尚未显式实例化的任何对象进行实例化。

您可以通过在函数模板主体中静态断言这 是您允许实例化的T类型之一来实现这一点。A,B,C...然后,如果它被实例化为T= Dstatic_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)() = &regular_func;
void (*ptr2)() = &template_func<int>;
void (*ptr3)() = &template_func<float>;
void (*ptr4)() = &template_func<char>; // <-- static_assert fails
Run Code Online (Sandbox Code Playgroud)