我试图使用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;
}
该代码在微软的编译器编译罚款,但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
其中线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;
}
...
(克++不complaing关于上面的代码)。
现在我的想法。 有什么问题? 有没有用gcc / g的问题++? 有没有我的代码合规问题?
我使用的编译器:
$ g++ --version
g++ (Ubuntu 4.3.3-5ubuntu4) 4.3.3
你可以用试试?
template<typename T>
int do_outer(T& val)
{
return val.get_inner().template get<int>();
}
我没有获得GCC个大气压,但我也有类似的问题,并添加模板关键字总是解决它们。 它工作在VS了。
为了给上为什么一些背景template
需要关键字:
template<typename T>
int do_outer(T& val)
{
int i;
val.get_inner().get<int>(i);
return i;
}
当编译器看到这个功能,它不知道什么类型val
是。 因此,它解析线val.get_inner().get(i)
如下:
1: val .
编译器看到.
所以可以假设,“VAL”具有类类型和下一标识符是一个成员对象或功能的名称。
2. val . get_inner (
val . get_inner (
get_inner
是该部件的名称,然后编译器看到(
,唯一的可能性是get_inner
是函数名,因此这是一个函数调用。然后它解析参数,直到它找到的闭合)
。
3. val . get_inner () .
val . get_inner () .
作为第一步骤,它现在知道因此它知道下一个标识符是一个成员对象或函数从get_inner返回必须是类的类型。
4. val . get_inner () . get <
val . get_inner () . get <
所以,你可以在<
可能是什么意思? 当然,它的模板参数开始...也许它的不到运营商?
我们知道, get
只能是一个对象或一个函数。 如果它是一个对象,则<
非常有意义作为除操作者的较少。 此外,只有其中名称之前,标准的更多或更少的状态<
是一个template-name
将它处理<
作为模板参数(14.2 / 3):
后名称查找(3.4)发现,一个名字是一个模板的名称,如果该名称后面是<
中, <
总是被作为模板参数列表的开始,从来没有像其次less-名称不是运营商。
在这种情况下,编译器不知道该表达式的类型是什么val.get_inner()
是,所以它无法查找get
。 它或多或少地假定,然后它的一个成员对象,而不是一个模板名称。 “<”被当作小于操作者和编译器结束了检查,如果get
小于int
-因此错误。
那么,为什么修复工作?
添加template
关键字
从字面上我们告诉编译器的get
是一个模板的名称,所以<
操作被视为一个模板参数列表的开始。
拆除模板参数
当do_outer没有模板参数,即: val . get_inner () . get (
val . get_inner () . get (
val . get_inner () . get (
编译器期望该成员get
是一个对象或功能的(
这两个名字被视为功能之间消歧。再后来模板参数推导出来的作品模板参数的类型。
我不能自称是一个哦10人在这个星球谁完全理解C ++模板,但你在这里所做的看起来好像没什么问题。 (它失败,GCC 4.4.1同样的错误,BTW)。
更改do_outer
到
const Inner& inner = val.get_inner();
return inner.get<int>();
与海湾合作委员会的工作,想必也将使用Visual C ++工作。
你可能会考虑向海湾合作委员会的错误; 要么他们会解决它,否则将被关闭为无效,并在这个过程中会有人希望解释为什么你在做什么是无效的代码。
进一步的更新和AHA:原来它不是真正有效的代码,GCC只是给出了一个可怕的错误消息。 英特尔C ++输出(实际上是有帮助的!)错误信息:
template.cpp(24): error: type name is not allowed
return val.get_inner().get<int>();
这让我意识到这个问题。 更改do_inner到
return val.get_inner().template get<int>();
该代码由两个ICC和GCC接受。