我正在玩一些静态多态性,我正在调用一个函数,该函数在内部根据初始参数的类型调用“正确的”专用函数(基本上我正在做标记)。代码如下:
#include <iostream>
using namespace std;
// tags
struct tag1{};
struct tag2{};
// the compliant types, all should typedef tag_type
struct my_type1
{
using tag_type = tag1;
};
struct my_type2
{
using tag_type = tag2;
};
// static dispatch via tagging
template <typename T>
void f(T)
{
cout << "In void f<typename T>(T)" << endl;
// why can I call f_helper without forward definition?!?
f_helper(typename T::tag_type{});
}
int main()
{
my_type1 type1;
my_type2 type2;
// how does f below knows about f_helper ?!?!
// even after instantiation f_helper shouldn't be visible!
f(type1);
f(type2);
}
// helper functions
void f_helper(tag1)
{
cout << "f called with my_type1" << endl;
}
void f_helper(tag2)
{
cout << "f called with my_type2" << endl;
}
所以,f(T)
是使用参数 my_type1
或 my_type2
调用的,该参数在内部必须 typedef tag_type
使用适当的标签 tag1
/tag2
。根据这个内部的tag_type
,“正确的”包装器会被调用,这个决定当然是在编译时做出的。现在我真的不明白为什么这段代码有效?为什么我们不需要前向声明 f_helper
?我首先在 main
之前(以及在 f
之后)定义了包装器,虽然没关系,但你不需要转发声明,因为编译器会实例化模板仅在调用 f(type1);
时(在 main()
中),在它不知道类型 T
之前,所以在编译器知道 f_wrapper
的实例化时间。
但正如您所见,即使我在 main()
之后声明了包装器,代码仍然有效。为什么会这样?我想这个问题有点奇怪,问为什么代码有效:)
编辑
即使在 gcc5 和 gcc HEAD 6.0.0 中,代码也会继续编译。
最佳答案
f_helper(typename T::tag_type{})
是一个依赖于类型的表达式,因为 T::tag_type
是依赖类型。这意味着 f_helper
在 f<T>
之前不需要可见由于两阶段查找而被实例化。
编辑:我很确定这实际上是未定义的行为。如果我们查看 14.6.4.2 [temp.dep.candidate],我们会看到以下段落:
For a function call that depends on a template parameter, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2, 3.4.3) except that:
— For the part of the lookup using unqualified name lookup (3.4.1) or qualified name lookup (3.4.3), only function declarations from the template definition context are found.
— For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.
If the function name is an unqualified-id and the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.
对我来说,最后一段表明这是未定义的行为。 function call that depends on a template parameter
这里是 f_helper(typename T::tag_type{})
. f_helper
在 f
时不可见是实例化的,但如果我们在编译所有翻译单元之后执行名称查找。
关于c++ - 为什么在通过模板进行静态调度时不需要前向声明?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25188353/