c – 默认模板类参数混淆g?
昨天我遇到一个g(3.4.6)编译器问题,我一直使用英特尔(9.0)编译器编译没有问题的代码.这是一个代码片段,显示了发生了什么:
template<typename A,typename B> class Foo { }; struct Bar { void method ( Foo<int,int> const& stuff = Foo<int,int>() ); }; g编译器错误是: foo.cpp:5: error: expected `,' or `...' before '>' token foo.cpp:5: error: wrong number of template arguments (1,should be 2) foo.cpp:2: error: provided for `template<class A,class B> struct Foo' foo.cpp:5: error: default argument missing for parameter 2 of `void Bar::method(const Foo<int,int>&,int)' 显然,以这种方式写入默认参数是不被接受的,而编译器则认为不是第二个模板参数,而是指定一个新的函数参数,因为该参数期望一个默认值,因为该参数有一个参数.我可以通过创建一个typedef来帮助编译器,然后一切都编译好: template<typename A,typename B> class Foo { }; struct Bar { typedef Foo<int,int> FooType; void method ( FooType const& stuff = FooType() ); }; 所以我可以解决我的问题,但我不明白发生了什么.我在这里错过了C(模板?)语言功能,我做错了,还是g编译器不接受第一段代码错误? 注意BTW,这也编译… template<typename A,typename B> class Foo { }; void method ( Foo<int,int>() ); 解决方法
我不太确定这是g中的一个bug(从4.2.4版本开始).代码现在通过g 4.4(参见下面的UPDATE).为了让这段代码为其他版本的编译器编译,您可以在默认参数周围添加一组括号:
template<typename A,typename B> class Foo { }; struct Bar { void method ( Foo<int,int> const& stuff = ( Foo<int,int>() ) ); }; IMO,这些括号是必需的,因为还有一个额外的要求,默认参数可以引用类的一个成员,该类的成员稍后可以在类体中被声明: struct Bar { void method ( int i = j); // 'j' not declared yet static const int j = 0; }; 上述代码是合法的,当“方法”的声明被解析时,成员’j’尚未被看到.因此,编译器只能使用语法检查(即匹配括号和逗号)来解析默认参数.当g解析您的原始声明时,实际看到的是: void method ( Foo<int,int> const& stuff = Foo<int // Arg 1 with dflt.,int>() ); // Arg 2 - syntax error 添加额外的括号集确保默认参数被正确处理. 以下情况显示了g成功但Comeau仍然生成语法错误的示例: template<int J,int K> class Foo { }; struct Bar { void method ( Foo<0,0> const & i = ( Foo<j,k> () ) ); static const int j = 0; static const int k = 0; }; 编辑: 响应评论:“你可以同样有一个函数调用有多个参数”,这不引起问题的原因是函数调用中的逗号在括号中包围: int foo (int,int,int); struct Bar { void method ( int j = foo (0,0) ); // Comma's here are inside ( ) }; 因此,可以使用表达式的语法来解析它.在C中,所有'(‘必须与’)匹配,因此这很容易解析.这里的问题的原因是’<'不需要匹配,因为它在C中重载,所以可以是少于操作符或模板参数列表的开始.以下示例显示'<'在默认参数中使用,暗示小于运算符: template<int I,int J> class Foo { }; struct Bar { template <typename T> struct Y { }; void method ( ::Foo<0,0> const& stuff = Foo<10,Y < int > = Y<int>() ); struct X { ::Foo<0,0> operator< (int); }; static X Foo; }; 上述“Foo <10”是对“运算符”的调用在“X”中定义,而不是模板参数列表的开头.再次,Comeau在上述代码上生成语法错误,g(包括3.2.3)正确解析. FYI,适当的参考文献是8.3.6 / 5中的注释:
然后在3.4.1 / 8
…
这里的子弹是强制编译器在默认参数的意义上“延迟”查找,直到所有的类成员都被声明为止. < UPDATE> 正如“已经雇用的俄罗斯人”所指出的,现在可以解释所有这些例子.不过,直到07年才被C标准委员会解决,我还没准备好把这个称作“错误”.我认为需要长期额外的括号才能确保对其他编译器/工具的可移植性(甚至是g的未来版本). 根据我的经验,C标准并不要求编译器供应商都应该使用相同的解析器技术,而且也不能指望所有技术同样强大.因此,解析要求通常不要求供应商执行超人的专长.为了说明这一点,请考虑以下两个示例: typedef T::TYPE TYPE; T::TYPE t; 如果“T”依赖,则给定每个上下文“TYPE”必须是一个typename,但是该标准仍然需要typename关键字.这些示例是明确的,只能表示一件事情,但是标准(为了允许所有解析器技术)仍然需要typename关键字. 可能的是,DR可能被解决,使得无法解析这些示例的编译器仍将是“标准符合”,只要额外的括号允许代码解析. < / UPDATE> (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |