我有一个返回字符串向量
的函数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> > >&)
为什么会发生此错误,我该怎么做才能将返回值直接传递给构造函数?
答案 0 :(得分:4)
为什么会发生此错误,我该怎么做才能将返回值直接传递给构造函数?
ValuesConstraint<>
的构造函数接受左值(对非const
的左值引用只能绑定到左值),而不返回引用类型的函数调用表达式是 rvalues
左值引用无法绑定到右值,因此您无法将临时值传递给ValuesConstraint<>
的构造函数(临时值是右值)。
如果您发现术语左值和右值令人困惑,您可以(直观地)将左值视为:
它们通常表示可以在程序中重复引用的对象,具有稳定的标识,从而隐式移动不安全(因为稍后可以在程序中引用它们)。
相反,您可以将rvalues视为:
42
,false
和3.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,以便从编译器收到警告并检测您正在使用此非标准扩展的情况。