2

我有一个返回字符串向量的函数

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> > >&)

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

4

1 回答 1

4

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

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

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

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

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

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

相反,您可以将右值视为:

  • 未命名的对象,例如临时对象;和/或
  • 文字(如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!

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

这发生在 GCC 4.4.7 而不是 VS2010

这是因为 VC10 实现了一个不符合标准的编译器扩展,它允许将右值绑定到对非const. 不过要注意,这不是标准行为,如果你想编写可移植的代码,你不应该依赖它(实际上我建议你不要依赖它)。

正如 Jesse Good 在评论中所建议的那样,将警告级别提高到 4 以便从编译器获得警告并检测您正在使用此非标准扩展的情况。

于 2013-07-08T20:49:02.963 回答