将从函数返回的向量传递给另一个函数

时间:2013-07-08 20:47:18

标签: c++ templates gcc4.7

我有一个返回字符串向量

的函数
std::vector<std::string> getNames()
{
std::vector<std::string> names;
names.push_back("one");
return names;
}

我有另一个带有以下签名的构造函数的类(这实际上是来自TCLAP):

ValuesConstraint(std::vector<T>& allowed);

如果我尝试执行以下操作,则会收到错误

ValuesConstraint<std::string> A( getNames() );

但不是在我做以下事情时

std::vector<std::string> v = getNames();
ValuesConstraint<std::string> A( v );

这发生在GCC 4.4.7中,但不在VS2010中。错误如下:

error: no matching function for call to ‘TCLAP::ValuesConstraint<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::ValuesConstraint(std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >)’

note: candidates are: TCLAP::ValuesConstraint<T>::ValuesConstraint(std::vector<T, std::allocator<_CharT> >&) [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]

note:                 TCLAP::ValuesConstraint<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::ValuesConstraint(const TCLAP::ValuesConstraint<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&)

为什么会发生此错误,我该怎么做才能将返回值直接传递给构造函数?

1 个答案:

答案 0 :(得分:4)

  

为什么会发生此错误,我该怎么做才能将返回值直接传递给构造函数?

ValuesConstraint<>的构造函数接受左值(对非const的左值引用只能绑定到左值),而不返回引用类型的函数调用表达式是 rvalues

左值引用无法绑定到右值,因此您无法将临时值传递给ValuesConstraint<>的构造函数(临时值是右值)。

如果您发现术语左值右值令人困惑,您可以(直观地)将左值视为:

  • 命名变量(实际上是标识符);和/或
  • 对象(实际上是表达式),您可以使用
  • 的地址

它们通常表示可以在程序中重复引用的对象,具有稳定的标识,从而隐式移动安全(因为稍后可以在程序中引用它们)。

相反,您可以将rvalues视为:

  • 像临时的未命名对象;和/或
  • 文字(例如42false3.14);和/或
  • 表示具有“不稳定”身份的对象的表达式(如std::move()的结果),即将从
  • 移出

它们通常表示不能在程序中重复引用的对象(或者承诺不再引用的对象,然后通过显式调用std::move()重新分配它们)因此,可以安全地离开。

尽管如此,可以采用上述方法 - 这只是一个指南,你可以用来建立一些关于什么价值类别的直觉,以及如何判断某个表达的价值类别是什么。在形式上,事情有点复杂,上述概括并不总是正确的。

在这种情况下回到你的榜样:

std::vector<std::string> v = getNames();
//                       ^
//                       Named variable! Can take its address! lvalue!
ValuesConstraint<std::string> A( v );
//                               ^
//                               OK! The constructor accepts an lvalue
//                               reference to non-const, and I am giving
//                               it an lvalue

您正在将左值传递给构造函数,一切正常。在这种情况下,另一方面:

ValuesConstraint<std::string> A( getNames() );
//                               ^^^^^^^^^^
//                               getNames() returns a vector by value, this
//                               means a temporary will be constructed as the
//                               return value of the function, and temporaries
//                               are unnamed... so, that's an rvalue!
//                               And the constructor accepts an lvalue reference
//                               to non-const! So this is an ERROR!

您正在尝试将rvalue传递给接受非const的左值引用的函数(换句话说,它需要一个可修改的左值)。这是非法的,编译器抱怨它。

  

这发生在GCC 4.4.7中,但不发生在VS2010中

这是因为VC10实现了一个不符合的编译器扩展,它允许绑定rvalues以对非const的引用进行左值化。请注意,这是标准行为,如果你想编写可移植代码,你不应该依赖它(我建议你不要依赖它,实际上)。 / p>

As suggested by Jesse Good in the comments,将警告级别提高到4,以便从编译器收到警告并检测您正在使用此非标准扩展的情况。