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>() );
解决方法
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
添加额外的括号集确保默认参数被正确处理.
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中的注释:
[Note: in member function declarations,names in default argument expressions are looked
up as described in 3.4.1…
然后在3.4.1 / 8
A name used in the definition of a member function (9.3) of class X following the function’s declaratorid29)
shall be declared in one of the following ways:
…
— shall be a member of class X or be a member of a base class of X (10.2),or
这里的子弹是强制编译器在默认参数的意义上“延迟”查找,直到所有的类成员都被声明为止.
< UPDATE>
正如“已经雇用的俄罗斯人”所指出的,现在可以解释所有这些例子.不过,直到07年才被C标准委员会解决,我还没准备好把这个称作“错误”.我认为需要长期额外的括号才能确保对其他编译器/工具的可移植性(甚至是g的未来版本).
根据我的经验,C标准并不要求编译器供应商都应该使用相同的解析器技术,而且也不能指望所有技术同样强大.因此,解析要求通常不要求供应商执行超人的专长.为了说明这一点,请考虑以下两个示例:
typedef T::TYPE TYPE; T::TYPE t;
如果“T”依赖,则给定每个上下文“TYPE”必须是一个typename,但是该标准仍然需要typename关键字.这些示例是明确的,只能表示一件事情,但是标准(为了允许所有解析器技术)仍然需要typename关键字.
可能的是,DR可能被解决,使得无法解析这些示例的编译器仍将是“标准符合”,只要额外的括号允许代码解析.
< / UPDATE>