为什么在推导类型时剥离模板参数的限定符?

时间:2010-11-12 12:10:00

标签: c++ visual-studio visual-studio-2008 templates

在使用Microsoft VisualStudio 2008构建一个小样本程序时,我注意到对传递给模板的类型的推断有些奇怪。考虑这个例子:

template<class T>
void f( T v ) {
    x; // trigger a compile error
    (void)v;
}

template<class T>
void g( T v ) {
    f( v );
}

void h() {
  int i;
  g<const int &>( i );
}

使用cl /c foo.cpp编译此示例会产生编译错误(按预期)。有趣的是'T'模板参数的值。以下是VisualStudio 2008的打印内容:

mini.cpp(3) : error C2065: 'x' : undeclared identifier
        mini.cpp(9) : see reference to function template instantiation 'void f<int>(T)' being compiled
        with
        [
            T=int
        ]
        mini.cpp(14) : see reference to function template instantiation 'void g<const int&>(T)' being compiled
        with
        [
            T=const int &
        ]

请注意,在g中,参数的类型为const int &,但在f中,它只是int。显然,在推断实例化f模板时要使用的类型时,剥离了引用到const的部分。调整示例时,调用f,如

f<T>( v );

const int &f中的类型为g。这是为什么?这是指定的行为吗?我秘密地依赖v函数参数的类型传递给f,但显然不是。

2 个答案:

答案 0 :(得分:6)

答案是虽然变量v的类型为const int &,但表达式 v是一个类型为const int的左值表达式。< / p>

litb提供文本(5/6):“如果表达式最初具有”对T的引用“类型(8.3.2,8.5.3),则在进行任何进一步分析之前将类型调整为”T“,表达式指定由引用表示的对象或函数,表达式是左值。“

“参数”是“由函数调用表达式中的括号限定的逗号分隔列表中的表达式”(1.3.1)。所以在14.8.2.1中:

  • “调用的相应参数类型(称之为A)”为const int
  • “如果A是cv限定类型,则类型推导会忽略A类型的顶级cv限定符”(因此,int)。
  • “扣除过程尝试查找模板参数值,使得推导出的A与A相同”(因此T为int

答案 1 :(得分:1)

http://accu.org/index.php/journals/409是一篇相当广泛的文章,但它解释了这个过程。从模板参数中,派生参数类型P,并将其与参数类型A匹配。相关部分描述了如何从函数参数派生目标类型A:对于非数组类型,简单地剥离引用。因此,如果参数的类型为int&,则目标类型A只是int

这是一个简单的原因:因为标准告诉了我们。理由是什么?碰巧的是,文章也有一个脚注指出了这一点。在您的示例中,typeid(v)==typeid(const int)。在非左值上下文中使用时,引用类型的行为类似于非引用类型。