c++ - 功能模板的部分属性在 GCC 中被静默忽略

标签 c++ c++11 gcc attributes

我试图将一组特定的函数放入一个单独的部分,但在使用 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>;

有了 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)() = &regular_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)() = &regular_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/

相关文章:

c++ - 使用 CreateRemoteThread 注入(inject) DLL

c++ - apache thrift 是否支持函数变量作为参数?

c++ - ARM GCC 堆未完全使用

iphone - 如何在 objective-c 和 xcode 中启用异常处理

c++ - 什么时候对流类型使用 std::swap?

c++ - `emit dataChanged( ... );` 不触发 View 显示更新的可能原因是什么?

c++ - 用cmake构建比特币

c++ - vector::push_back 和 std::move

c++ - 如何在多映射中将结构累积为值类型?

python - 当我尝试安装 readline-6.2 时出现 gcc 错误