题
昨天我跑进一个克++代码(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)'
显然,默认参数不被写入这样,当接受,并且编译器假定代替第二模板参数指定新的函数的参数,为此,它然后期望的默认值,因为stuff
参数有一个。我可以通过创建一个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> const& stuff = Foo<int,int>() );
解决方案
我不能肯定,这是克的错误++(因为4.2.4版本)。现在,该代码通过以g ++ 4.4(见下文更新)。为了对编译器的其它版本的代码编译,您可以添加周围的默认参数括号的一组:
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 ++成功的例子,但仍然科莫产生语法错误:
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, 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;
};
上面的“富<10”是将“操作者<”在“X”,而不是模板参数列表的开始定义一个呼叫。再次,科莫生成上述代码和g语法错误++(包括3.2.3)正确地解析此。
FYI,适当的参考文献是在8.3.6 / 5的说明:
[注:在构件函数声明,在默认参数表达式名称都 向上如在3.4.1中描述...
和然后在3.4.1 / 8
在下面的函数的declaratorid29类X的成员函数(9.3)的定义中使用的名称) 应以下列方式之一进行声明:
...
- 须类X的成员,或者是基类X的(10.2),或
的成员
下面这个子弹,是强制编译器为默认的说法,直到所有的类成员已宣布的意思是“延迟”查找的部分。
<强>
如由“就业俄罗斯”指出,克++ 4.4现在能够解析所有的这些实施例。然而,直到 DR 已解决由C ++标准委员会,我还没有准备好称这是一个“错误”。我相信,长期额外的括号将需要确保移植到其他的编译器/工具(和g ++的甚至将来的版本)。
据我的经验,C ++标准没有规定编译器厂商都应该使用相同的解析器技术,而且他们也不能指望所有的技术都同样强大。其结果是,解析需求通常不要求供应商执行超人的壮举。为了说明这一点考虑以下两个例子:
typedef T::TYPE TYPE;
T::TYPE t;
如果 'T' 是相关的,则给定的每个上下文 '类型' 的必须强>是类型名,然而,标准仍然需要类型名称关键字。这些例子是明确和Cañ只能意味着一两件事,但是标准(为了让所有的解析器技术)仍然需要的类型名称的关键字。
这有可能是在DR可以以这样的方式,从而未能分析这些示例的编译器仍然将是“符合标准的”,只要额外的括号允许代码来解析得到解决。
<强> 强>
其他提示
这是一个已知的臭虫GCC 。 它已被固定在GCC-4.4,其编译原始源就好了。
看起来像一个编译错误。我尝试了在IBM的xlc编译V7.0(我已经发现是更符合标准的比GCC)和它编译好的。
template <bool> class A {};
typedef A<static_cast<bool>(1>0)> B;//buggy
int main() { B b; }