如果您阅读的代码如下
auto&& var = foo();
where foo是按类型值返回的任何函数T.然后var是左值类型的左值引用T.但这意味着var什么呢?这是不是意味着,我们被允许窃取资源var?是否有任何合理的情况,您应该使用auto&&告诉读者您的代码与您在返回时unique_ptr<>告诉您拥有独占所有权时的行为?例如什么T&&时候T类型?
我只是想了解,如果有任何其他用例auto&&比模板编程中的用例; 喜欢这篇文章中的例子中所讨论的那些通用参考斯科特迈尔斯.
此函数的参数将绑定到右值引用:
void f(int && i);
Run Code Online (Sandbox Code Playgroud)
但是,此函数的参数将绑定到右值或左值引用:
template <typename T>
void f(T && t);
Run Code Online (Sandbox Code Playgroud)
我经常听到这被称为通用参考.
我也听说它被称为转发参考.
他们的意思是一样的吗?
如果函数体调用,它只是转发引用std::forward吗?
c++ templates perfect-forwarding universal-reference forwarding-reference
假设我使用基于范围的循环编程时的当前规则说
使用
for(auto const &e :...)或for(auto &e:...)在可能时使用for(auto a: ...).
我以我自己的经验和这个问题为例.
但是在读完关于循环的新简洁之后我想知道,我不应该用我&的规则替换我的规则&&吗?正如这里所写,这看起来像迈耶斯的通用参考.
所以,我问自己,如果我的新规则要么
使用
for(auto const &&e :...)或for(auto &&e:...)在可能的时候......
或者这不总是有效,因此应该是相当复杂的
检查
for(auto const &&e :...)或者for(auto &&e:...)是可能的,再考虑for(auto const &e :...)或者for(auto &e:...),并且只在需要时不使用引用.
这是一个右值参考:
void foo(int&& a);
Run Code Online (Sandbox Code Playgroud)
它不绑定到左值:
int i = 42;
foo(i); // error
Run Code Online (Sandbox Code Playgroud)
这是一个普遍的参考:
template<typename T>
void bar(T&& b);
Run Code Online (Sandbox Code Playgroud)
它绑定到右值,它也绑定到左值:
bar(i); // okay
Run Code Online (Sandbox Code Playgroud)
这是一个右值参考:
template<typename T>
struct X
{
void baz(T&& c);
};
Run Code Online (Sandbox Code Playgroud)
它不绑定到左值:
X<int> x;
x.baz(i); // error
Run Code Online (Sandbox Code Playgroud)
为什么通用引用使用与右值引用相同的语法?这不是一个不必要的混乱来源吗?难道该委员会曾经考虑替代语法像T&&&,T&*,T@或T&42(开玩笑的对最后一个)?如果是这样,拒绝替代语法的原因是什么?
c++ language-design rvalue-reference c++11 forwarding-reference
我知道如果声明变量或参数具有T&&某种推导类型的类型T,那么该变量或参数通常被称为通用引用.
Scott Meyers在其最初的演讲"C++ 11中的通用参考"中引入了 通用参考这一术语.但是,我想知道普遍参考的官方/标准术语是什么.
我一直在阅读Scott关于c ++ 11和14的最后一篇大师文章中的通用引用,尽管有一个参数分配给左值或右值类型的参考参数,但在它们之间存在一些被称为通用引用的东西,它可以推导出来l/rvalue基于传递的参数的类型特征.我可以理解是什么使得参数成为通用引用但是我不清楚的一个原因是为什么在类型参数中添加const const T&& p使得p为rvalue:
template<typename T>
void f(T&& param); // param is an universal reference
template<typename T>
void f(const T&& param); // param is an rvalue reference
Run Code Online (Sandbox Code Playgroud)
const分配给参考参数时,是否会执行此操作.
在这个例子中,Scott Meyers明确了rvalue引用和转发引用之间的区别:
Widget&& var1 = someWidget; // here, “&&” means rvalue reference (1)
auto&& var2 = var1; // here, “&&” does not mean rvalue reference (2)
template<typename T>
void f(std::vector<T>&& param); // here, “&&” means rvalue reference (3)
template<typename T>
void f(T&& param); // here, “&&”does not mean rvalue reference (4)
Run Code Online (Sandbox Code Playgroud)
本质上,当我们有一个可推导的上下文时就会出现这种区别,因此案例(3)明确表明我们有一个,vector<...>&&而T案例(4)是要推断的,并且(在应用参考折叠规则之后)按"价值类别"分类.
但是更复杂的模式匹配会发生什么?以下面的情况为例:
template <template <class...> class Tuple, class... Ts>
void f(Tuple<Ts...>&& arg)
{
}
Run Code Online (Sandbox Code Playgroud)
&&这里的意思是什么?
在使用通用引用的同时,我遇到了clang和gcc在重载决策上不一致的情况.
#include <iostream>
struct foo {};
template<typename T>
void bar(T&) { std::cout << "void bar(T&)\n"; }
template<typename T>
void bar(T&&) { std::cout << "void bar(T&&)\n"; }
int main()
{
foo f;
bar(f); // ambiguous on gcc, ok on clang
}
Run Code Online (Sandbox Code Playgroud)
gcc报告上面的调用是模棱两可的.但是,clang选择T&重载并成功编译.
哪个编译器有问题,为什么?
编辑:
在VS2013预览中测试相同的代码,它同意clang; 除了Intellisense,这是在gcc的一方:-)
c++ overload-resolution c++11 universal-reference forwarding-reference
Herb Sutter 回归基础!CppCon 上的现代C++演示要点讨论了传递参数的不同选项,并将其性能与写作/教学的简易性进行了比较."高级"选项(在所有测试的案例中提供最佳性能,但对大多数开发人员来说难以编写)是完美转发,给出了示例(PDF,第28页):
class employee {
std::string name_;
public:
template <class String,
class = std::enable_if_t<!std::is_same<std::decay_t<String>,
std::string>::value>>
void set_name(String &&name) noexcept(
std::is_nothrow_assignable<std::string &, String>::value) {
name_ = std::forward<String>(name);
}
};
Run Code Online (Sandbox Code Playgroud)
该示例使用带转发引用的模板函数,模板参数String使用约束enable_if.然而,约束似乎是不正确的:似乎只有在String类型不是a 时才使用此方法std::string,这没有任何意义.这将意味着该std::string成员可以使用设置什么,但一个std::string值.
using namespace std::string_literals;
employee e;
e.set_name("Bob"s); // error
Run Code Online (Sandbox Code Playgroud)
我考虑的一个解释是,有一个简单的拼写错误,而且约束的目的是std::is_same<std::decay_t<String>, std::string>::value代替!std::is_same<std::decay_t<String>, std::string>::value.然而,这意味着setter不能使用,例如,const char *它显然是打算使用这种类型,因为这是在演示文稿中测试的案例之一.
在我看来,正确的约束更像是:
template <class String,
class = std::enable_if_t<std::is_assignable<decltype((name_)),
String>::value>>
void set_name(String &&name) …Run Code Online (Sandbox Code Playgroud) #include <vector>
using namespace std;
template<typename T, typename = decltype(&T::size)>
void f1(T)
{}
template<typename T, typename = decltype(&T::size)>
void f2(T&)
{}
template<typename T, typename = decltype(&T::size)>
void f3(T&&)
{}
int main()
{
vector<int> coll;
f1(coll); // ok
f2(coll); // ok
f3(coll); // error : no matching function for call to 'f3'
}
Run Code Online (Sandbox Code Playgroud)
main.cpp(21,6):注意:候选模板被忽略:替换失败[with
T=>std::vector<int, std::allocator<int> > &]:类型'std::vector<int, std::allocator<int> > &'在'::' 之前不能使用,因为它没有成员
void f3(T&&)
我的编译器是clang 4.0.
令我惊讶的是,f3(coll)失败了,f1(coll)而且f2(coll)都很好.
为什么转发引用在这种情况下不起作用?