在获取地址时,有关模板类型(类/函数)实例化的规则是什么?

Nim*_*Nim 6 c++ templates

在回答这个问题时,我在模板实例化方面遇到了这种行为差异.

最初有一个功能模板

template <typename T> void my_callback(void* data) { … }
Run Code Online (Sandbox Code Playgroud)

现在有些东西需要这个地址 - 特别是a void*,所以显而易见的方法是

bar(reinterpret_cast<void*>(&my_callback<int>));
Run Code Online (Sandbox Code Playgroud)

但是,对于gcc 4.5之前的编译器版本,这会导致上下文错误...错误.好 - 所以修复是先"强制转换" - 强制实例化,即:

void (*callback)(void*) = my_callback<int>;
bar(reinterpret_cast<void*>(callback));
Run Code Online (Sandbox Code Playgroud)

这很好用.

现在是第二种情况,它不是一个自由函数,而是一个类模板的静态成员,即

template <typename T>
struct foo
{
  static void my_callback(void* data) {
    T& x = *static_cast<T*>(data);
    std:: cout << "Call[T] with " << x << std::endl;
  }
};
Run Code Online (Sandbox Code Playgroud)

现在,原作reinterpret_cast好了.

bar(reinterpret_cast<void*>(&foo<int>::my_callback));
Run Code Online (Sandbox Code Playgroud)

所以我的问题是 - 为什么这种明显的行为差异?

Luc*_*ton 2

来自 n3290,14.7.1 隐式实例化 [temp.inst]

2 除非函数模板特化已被显式实例化或显式特化,否则当在需要函数定义存在的上下文中引用该特化时,该函数模板特化将被隐式实例化。

第 1 段中对于类模板特化也有类似的规则。请注意,该标准是用专业化来表述的,因为在使用模板时会隐式声明专业化,这里没有用户提供的专业化,至少对于函数模板而言(第 8 段)。

结合第10段,

10 实现不得隐式实例化不需要实例化的函数模板、成员模板、非虚成员函数、成员类或类模板的静态数据成员。

我认为经验法则是:一旦需要对象/类成员/函数或使程序正常工作(非正式地说),模板就会隐式实例化,但不会更快。这包括获取函数的地址。

至于您链接的问题,某些使用reinterpret_cast可能会使程序不符合要求,此时提及实例化已经无关紧要了——我邀请您在那里查看我的答案</无耻>。