This may be a little comfort, but GCC agrees if you apply the section
attribute to an explicit instance of template <class T> void template_func()
, for each T
that you want to create, for example,
namespace { [[gnu::section(".mysection")]] void regular_func() { } template <class T> void template_func() { } template [[gnu::section(".mysection")]] void template_func<int>(); }
Then:
$ g++ -std=c++14 a.cpp -c && objdump -C -t ao | grep -E "regular|template" 0000000000000000 l F .mysection 0000000000000007 (anonymous namespace)::regular_func() 0000000000000007 l F .mysection 0000000000000007 void (anonymous namespace)::template_func<int>()
Unfortunately, clang rejects:
template [[gnu::section(".mysection")]] void template_func<int>();
saying:
template [[gnu::section(".mysection")]] void template_func<int>(); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: an attribute list cannot appear here
therefore, each compiler must have its own path through conditional compilation.
In addition, this fix brings an additional headache that you must somehow ensure that template_func()
cannot be created for any T
that you did not explicitly specify instantiated.
You can achieve this by statically asserting in the body of the function template that T
is one of the types A,B,C...
that you allow to create. Then, if it is always created using T
= D
, static_assert
triggered; you can add D
to the list and add an explicit instance for 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