为什么不需要通过模板在静态调度中进行前向声明?

2024-05-19

我正在玩一点静态多态性,我正在调用一个函数,该函数根据初始参数的类型在内部调用“正确的”专用函数(基本上我正在做标记)。这是代码:

#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(使用前将#替换为@)

为什么不需要通过模板在静态调度中进行前向声明? 的相关文章

随机推荐