g ++不喜欢模板方法链接模板var吗?

Rôm*_*con 5 c++ compiler-construction gcc templates g++

我正在尝试用g ++编译一些以前在Visual C++ 2008 Express Edition下开发的代码,看起来g ++不会让我在模板变量方法返回的引用上调用模板方法.我能够将问题缩小到以下代码:

class Inner
{
public:
  template<typename T>
  T get() const
  {
    return static_cast<T>(value_);
  };
private:
  int value_;
};

class Outer
{
public:
  Inner const& get_inner() { return inner_; };
private:
  Inner inner_;
};

template<typename T>
int do_outer(T& val)
{
  return val.get_inner().get<int>();
}

int main()
{
  Outer outer;
  do_outer(outer);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

代码在Microsoft的编译器下编译得很好,但是g ++会抛出一个错误:

$ g++ -c main.cpp
main.cpp: In function ‘int do_outer(T&)’:
main.cpp:24: error: expected primary-expression before ‘int’
main.cpp:24: error: expected ‘;’ before ‘int’
main.cpp:24: error: expected unqualified-id before ‘>’ token
Run Code Online (Sandbox Code Playgroud)

第24行所指的地方return val.get_inner().get<int>();.

如果我do_outer使用正常方法接收Outer引用,则代码编译.制作Inner::get()正常方法也有效.使Inner::get()返回void和接收模板参数也有效,因为下面的int说明符变得不必要,即:

class Inner
{
public:
  template<typename T>
  void get(T& val) const
  {
    val = static_cast<T>(value_);
  };
private:
  int value_;
};

...

template<typename T>
int do_outer(T& val)
{
  int i;
  val.get_inner().get(i);
  return i;
}

...
Run Code Online (Sandbox Code Playgroud)

(g ++不会抱怨上面的代码.)

现在我没有想法了.有什么问题?gcc/g ++有问题吗?我的代码是否存在合规性问题?

我正在使用的编译器是:

$ g++ --version
g++ (Ubuntu 4.3.3-5ubuntu4) 4.3.3
Run Code Online (Sandbox Code Playgroud)

Ric*_*den 11

只是为了说明为什么template需要关键字的背景:

template<typename T>
int do_outer(T& val)
{
  int i;
  val.get_inner().get<int>(i);
  return i;
}
Run Code Online (Sandbox Code Playgroud)

当编译器看到这个函数时,它不知道它的类型val是什么.因此它val.get_inner().get(i)按如下方式解析该行:

1: val .

编译器看到.,因此可以假设'val'具有类类型,下一个标识符是成员对象或函数的名称.

2. val . get_inner (

get_inner是成员的名称,然后编译器看到(.唯一的可能是get_inner函数名称,所以这是一个函数调用.然后它解析参数,直到找到结束).

3. val . get_inner () .

至于第一步,它现在知道get_inner的返回必须是类类型,因此它知道下一个标识符是成员对象或函数.

4. val . get_inner () . get <

那么,<可能意味着什么呢?当然它是模板参数的开始......或者它可能是小于运算符?

我们知道get只能是一个对象或一个函数.如果它是一个物体,那么<作为一个小于运算符就是完美的意义.此外,标准或多或少表明只有在<a 之前的名称才会template-name将它<视为模板参数(14.2/3):

在名称查找(3.4)发现名称是模板名称后,如果此名称后跟a <,<则始终将其作为模板参数列表的开头,并且永远不会作为名称后跟小于运算符.

在这种情况下,编译器不知道表达式的类型是什么val.get_inner(),因此无法查找get.它或多或少地假定它是成员对象而不是模板名称.'<'被视为小于运算符,编译器最终检查是否get小于int- 因此错误.

那么,为什么修复工作?

添加template关键字

从字面上看,我们告诉编译器它get是一个模板名称,因此<操作符被视为模板参数列表的开头.

删除模板参数

当do_outer没有模板参数时,即:val . get_inner () . get (编译器期望该成员get是对象或函数.这(两者之间的歧义和名称被视为一种功能.稍后模板参数推导然后计算出模板参数的类型.


sti*_*ijn 8

你可以试试吗?

template<typename T>
int do_outer(T& val)
{
  return val.get_inner().template get<int>();
}
Run Code Online (Sandbox Code Playgroud)

我无法访问gcc atm,但我遇到了类似的问题,添加模板关键字总能解决它们.它也适用于VS.

  • 这有效.另见:http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/keyword_template_qualifier.htm (2认同)