【问题标题】:C++ name resolution for member functions in template class模板类中成员函数的 C++ 名称解析
【发布时间】:2015-06-19 14:52:13
【问题描述】:
#include <iostream>

template<class T> struct A {
    typedef T a; 
}; 
template<class T> 
struct B {
    typedef typename A<T>::a a;
    static a foo(a b); 
}; 
template<class T> 
a B<T>::foo(a b) {return b}

int main() {
    std::cout << B<int>::foo(1); 
}

给出以下错误:(try it)。

main.cpp:13:1: error: 'a' does not name a type
    a B<T>::foo(a b) {return b}

内联定义不会出现此错误。

谁能解释一下为什么在这种情况下编译器无法解析a,以及如何使这段代码工作。

我不想明确解析所有的名称

typename B<T>::a B<T>::foo(typename B<T>::a b) {return b}

因为它会降低可读性。

【问题讨论】:

标签: c++ templates


【解决方案1】:

那是因为这里的 a 仍在全局范围内:

template<class T> 
a B<T>::foo(a b) {return b;}
^^

您正在对a 进行非限定查找。一旦您到达定义的B&lt;T&gt;:: 部分,该范围就会添加到所有进一步的查找中。所以参数b的类型会在B&lt;T&gt;的范围内查找。

您只需将其限定为返回类型:

template<class T> 
typename B<T>::a B<T>::foo(a b) {return b;}

关于为什么可以找到参数类型a的相关规则在[basic.lookup.unqual]/8中:

对于类 X 的成员,在成员函数体、默认参数、异常规范中使用的名称, 在非静态数据成员 (9.2) 的大括号或等号初始化程序中,或在类的定义中 X 定义之外的成员,在成员的声明符 id 之后,应在其中一个声明 以下方式:
— 在其用于使用它的块或封闭块(6.3)之前,或
— 应为 X 类的成员或 X (10.2) 的基类的成员,或

返回类型 a 与粗体文本(或上述任何文本)不匹配,但参数类型 a 匹配。

【讨论】:

  • 参数类型不在成员函数体中。它是“在 X 定义之外的类成员的定义中,在成员的 declarator-id 之后”。
【解决方案2】:

如果是 C++11 和 14,您可以声明您的函数 auto 以摆脱长返回类型。您需要在 C++11 中将其指定为尾随类型,但这允许您省略 typename B&lt;T&gt;::,因为编译器已经知道在哪里查找。

//C++11
template<class T>
auto B<T>::foo(a b) -> a {return b;}

//C++14
template<class T>
auto B<T>::foo(a b) {return b;}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多