昨天我跑进一个克++代码(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; }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top