构造函数按值接收两个参数时出错

时间:2016-02-29 16:21:41

标签: c++ c++11 c++14

有时为了简单和高效,我发现使用这种类型的迭代器非常有用:

// Chunk 1
    template <class Itor1, class Itor2 = Itor1>
class Pair_Iterator
{
  Itor1 it1;
  Itor2 it2;

public:

  Pair_Iterator(Itor1 i1, Itor2 i2) : it1(i1), it2(i2) {}

  bool has_curr() const { return it1.has_curr() and it2.has_curr(); }

  auto get_curr() const
  {
    return std::make_pair(it1.get_curr(), it2.get_curr());
  }

  void next()
  {
    it1.next();
    it2.next();
  }
};

这个想法是通过迭代器同时遍历两个不同类型的容器。

现在,由于我无法理解的原因,下一个测试无法编译:

// previous chunk could be included here
struct It1
{
  It1() {}
  bool has_curr() const { return true; }
  int get_curr() const { return 1; }
  void next() {}
};

int main()
{
  for (Pair_Iterator<It1> it(It1(), It1()); it.has_curr(); it.next())
    ;
}

clang编译器(版本3.8)说:

error: member reference base type 'Pair_Iterator<It1> (It1 (*)(), It1 (*)())'
      is not a structure or union
  for (Pair_Iterator<It1> it(It1(), It1()); it.has_curr(); it.next())
                                            ~~^~~~~~~~~
it.C:57:62: error: member reference base type 'Pair_Iterator<It1> (It1 (*)(), It1 (*)())'
      is not a structure or union
  for (Pair_Iterator<It1> it(It1(), It1()); it.has_curr(); it.next())
                                                       ~~^~~~~

gnu编译器(版本5.3)说:

error: request for member ‘has_curr’ in ‘it’, which is of non-class type ‘Pair_Iterator<It1>(It1 (*)(), It1 (*)())’
   for (Pair_Iterator<It1> it(It1(), It1()); it.has_curr(); it.next())
                                                ^
it.C:57:63: error: request for member ‘next’ in ‘it’, which is of non-class type ‘Pair_Iterator<It1>(It1 (*)(), It1 (*)())’
   for (Pair_Iterator<It1> it(It1(), It1()); it.has_curr(); it.next())

但是,如果我通过:

更改Pair_Iterator实例化
It1 it1;
for (Pair_Iterator<It1> it(it1, It1()); it.has_curr(); it.next())

然后一切都完美地汇编。

所以我的问题是:

  1. 为什么第一个实例化无效(我认为因为两个编译器拒绝它)
  2. 有没有办法写Pair_Iterator以便实例化利息?

1 个答案:

答案 0 :(得分:10)

你加入了全球数百万与Most Vexing Parse挣扎的人。

Pair_Iterator<It1> it(It1(), It1())

这被解释为一个函数,它接受函数返回It1的两个指针,然后返回Pair_Iterator<It1>。使用统一初始化语法来解决它,或将它们包装在额外的括号中。

Pair_Iterator<It1> it{It1(), It1()}

在第二种情况下成功,因为It()是一个后跟括号的类型,所以它可能是一个函数类型。但是,变量的名称强制编译器意识到它正在实例化一个新变量,而不是声明一个函数。

通常,当表达式看起来像type name(type(), type())时,应将其替换为:

type name{type(), type()}
//or
type name = type(type(), type())
//or
type name((type()), (type()))

type()参数的数量并不重要; type name(type())type name(type(), type(), type())遇到同样的问题。