我正在玩一点静态多态性,我正在调用一个函数,该函数根据初始参数的类型在内部调用“正确的”专用函数(基本上我正在做标记)。这是代码:
#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;
}
So, f(T)
使用参数调用my_type1
or my_type2
内部必须 typedeftag_type
带有适当的标签tag1
/tag2
。取决于这个内部tag_type
,然后调用“正确的”包装器,这个决定当然是在编译时做出的。现在我真的不明白为什么这段代码可以工作?为什么我们不需要前向声明f_helper
?我首先定义了包装器main
(之后f
),我认为好吧,这是有道理的,您不需要转发声明,因为编译器仅在以下情况下实例化模板f(type1);
被称为(在main()
), 在它不知道类型之前T
,所以在实例化时编译器知道f_wrapper
.
但正如你所看到的,即使我在之后声明包装器main()
,代码仍然有效。为什么会发生这种情况?我想这个问题有点奇怪,问为什么代码有效:)
EDIT
即使在 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],我们会看到以下段落:
对于依赖于模板参数的函数调用,
使用通常的查找规则(3.4.1,
3.4.2、3.4.3),但以下情况除外:
— 对于使用非限定名称查找(3.4.1)或限定名称查找(3.4.3)的查找部分,仅
找到来自模板定义上下文的函数声明。
— 对于使用关联命名空间的查找部分(3.4.2),仅
在模板定义上下文中找到的函数声明
或者找到模板实例化上下文。
如果函数名
是一个不合格的 ID,并且调用将是格式不正确的或者会找到一个
更好的匹配是在关联的命名空间内进行查找
考虑了所有具有外部链接的函数声明
在所有翻译单元的这些命名空间中引入,而不仅仅是
考虑在模板定义中找到的那些声明和
模板实例化上下文,则程序未定义
行为。
对我来说,最后一段表明这是未定义的行为。这function call that depends on a template parameter
这是f_helper(typename T::tag_type{})
. f_helper
不可见时f
已实例化,但如果我们在编译所有翻译单元后执行名称查找,则会出现这种情况。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)