为什么一个std::thread对象通过转发引用接受函数参数,然后用decay_copy?复制该对象?按值接受函数对象会不会更容易?
一般来说为什么不模拟函数以便按值获取函数对象?可以引用 - 不能用reference_wrappers 模仿(这将更明确,并且还方便地有一个成员operator()来调用存储的函数)?
假设我想创建一个函数,通过引用获取左值和右值字符串参数,将它们转换为大写,并将它们打印到标准输出:
void upper_print(std::string& s);
void upper_print(std::string&& s);
Run Code Online (Sandbox Code Playgroud)
这工作正常如下:
std::string s("Hello world");
upper_print(s);
upper_print(std::string("Hello world"));
upper_print("Hello world"); // converting ctor used
Run Code Online (Sandbox Code Playgroud)
但是,为避免冗余,我想使用转发引用:
template <typename T> upper_print(T&& s);
Run Code Online (Sandbox Code Playgroud)
不幸的是,我无法upper_print使用字符串文字参数调用:
std::string s("Hello world"); // OK
upper_print(s); // OK
upper_print(std::string("Hello world")); // OK
upper_print("Hello world"); // ERROR
Run Code Online (Sandbox Code Playgroud)
我知道可以限制std::string对象的参数,例如,使用std::enable_if或static_assert.但这并没有帮助.
在这个意义上,是否有任何选项可以结合转发引用和转换构造函数的功能?
在cppreference上,写道正确的使用方法std::result_of是:
template<class F, class... Args>
std::result_of_t<F&&(Args&&...)>
// instead of std::result_of_t<F(Args...)>, which is wrong
my_invoke(F&& f, Args&&... args) {
/* implementation */
}
Run Code Online (Sandbox Code Playgroud)
我想知道std::invoke_result_t应该如何使用
invoke_result_t:
template<class F, class... Args>
std::invoke_result_t<F&&, Args&&...> my_invoke(F&& f, Args&&... args);
Run Code Online (Sandbox Code Playgroud)
要么:
template<class F, class... Args>
std::invoke_result_t<F, Args...> my_invoke(F&& f, Args&&... args);
Run Code Online (Sandbox Code Playgroud) 下面的代码标准正确吗?(天马行空)
即 by-ref 捕获表示临时的转发引用,并在同一表达式中从函数返回结果 lambda 值。
当然,存储 lambda 以供以后使用会使它包含一个悬空引用,但我指的是main.
我的疑虑与这个 SO answer和潜在的这种语言缺陷有关。具体来说,有一个令人生畏的评论说“标准引用中的引用捕获生命周期规则捕获了变量,而不是数据及其范围” ——这似乎是说捕获的临时引用在我的代码中可能是无效的。
#include <stdlib.h>
#include <string.h>
#include <cassert>
template<typename F>
auto invoke(F&& f)
{
return f();
}
template<typename F>
auto wrap(F&& f)
{
return [&f]() {return f();}; // <- this by-ref capture here
}
int main()
{
int t = invoke(wrap(
[]() {return 17;}
));
assert(t == 17);
return t;
}
Run Code Online (Sandbox Code Playgroud) 我想创建一个宏,将一对解包为两个局部变量.如果它只是一个变量,我想不创建该对的副本,这将实现:
#define UNPACK_PAIR(V1, V2, PAIR) \
auto& V1 = PAIR.first; \
auto& V2 = PAIR.second;
UNPACK_PAIR(one, two, x);
Run Code Online (Sandbox Code Playgroud)
但是,我也希望它不要评估多次给出的表达式,例如这应该只调用expensive_computation()一次:
UNPACK_PAIR(one, two, expensive_computation());
Run Code Online (Sandbox Code Playgroud)
如果我做:
#define UNPACK_PAIR_A(V1, V2, PAIR) \
auto tmp = PAIR; \
auto& V1 = tmp.first; \
auto& V2 = tmp.second;
Run Code Online (Sandbox Code Playgroud)
然后它适用于expensive_computation()案例,但它在x案件中复制.如果我做:
#define UNPACK_PAIR_R(V1, V2, PAIR) \
auto& tmp = PAIR; \
auto& V1 = tmp.first; \
auto& V2 = tmp.second;
Run Code Online (Sandbox Code Playgroud)
然后它在x没有复制的情况下工作,但在这种expensive_computation()情况下失败.如果我做:
#define UNPACK_PAIR_CR(V1, V2, PAIR) \
const auto& …Run Code Online (Sandbox Code Playgroud) 我想编写一个foo应该调用operator()其参数的函数,如下面(破碎)代码所示:
template <typename T> void foo(const T& x){
x();
}
struct MyFunctor{
int data;
void operator()(){
/* stuff that might modify the data */
}
};
int main()
{
foo(MyFunctor{});
}
Run Code Online (Sandbox Code Playgroud)
显然代码不起作用,因为operator()它是非的const,但foo()需要它的参数const.
作为模板函数,foo()应该使用两个const和非const函子,并且不要挑剔const它的参数的性质.
如果我foo()通过删除const以下内容进行更改:
template <typename T> void foo(T& x) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
...它也不起作用,因为你无法将右值引用转换为非const左值引用,因此foo(MyFunctor{})无法调用.
更改foo()为转发引用可解决所有问题:
template <typename T> …Run Code Online (Sandbox Code Playgroud) 根据cppreference.com,move有签名
template< class T >
typename std::remove_reference<T>::type&& move( T&& t ) noexcept;
Run Code Online (Sandbox Code Playgroud)
为什么它需要一个右值参考T&& t作为它的arugment?
当我尝试以下代码时
void foo(int&& bar) {
cout << "baz" << endl;
}
int main(){
int a;
foo(a);
}
Run Code Online (Sandbox Code Playgroud)
我从编译器得到一个错误"rvalue引用不能绑定到左值"
到底是怎么回事?我很困惑.
我将lambda传递给一个函数,该函数接受它作为r值引用.
如果我的lambda是在函数调用本身中定义的,那我以后真的不关心它会发生什么.
但是如果我的lambda是一个变量(假设我想多次使用它),我确实想知道它不是移动的.
是否有办法知道它是否会被移动 - 在呼叫返回后使其无法使用或相应可用?
编辑:
只是为了澄清,lambda没有捕获任何东西.我关心的是仿函数本身:auto fn = [](int a){ return a; };
让我更难.我将传递函数作为右值:std::move(fn)
std :: move只是一个演员.它不移动任何东西,但被调用者中的rvalue参数现在绑定到正确的右值.
问题是,fn保证会被感动吗?是否保证不被感动?有什么保证吗?我可以让它以这种方式或那种方式运行,还是由被调用者来做?
我想知道,因为我想知道我可以fn作为函数参数传递两次.
编辑#2:
我们来看另一个案例吧.我必须用容器调用一个函数.矢量,地图或其他任何东西.功能签名说&&.我可以使用std move或std向前包装我的容器以获得rvalue ref到被调用者.这真是一回事,因为他们都是美化的演员.
现在,让我们说我使用std前进因为我真的很喜欢我的容器不能去任何地方.
我很容易看到被叫方没有意识到我的意图,并且在通话结束后移动我的容器使其无效(内脏).这是语言缺陷还是我错过了什么?
转发参考应该将参数转发给另一个函数,对吗?那么为什么它不是const?
template <typename T>
void func(const T&&);
Run Code Online (Sandbox Code Playgroud)
非常量引用允许函数修改其参数(而不是仅转发参数)。
来自 ISO 标准(准确地说是 N4860)的std::pair概要:
constexpr explicit(see below) pair(const T1& x, const T2& y); // first constructor
template<class U1, class U2>
constexpr explicit(see below) pair(U1&& x, U2&& y); // second constructor
Run Code Online (Sandbox Code Playgroud)
我似乎找不到任何理由为什么第一个构造函数应该与完美转发构造函数一起定义。完美的转发构造函数是否足以处理复制、移动两种情况?在哪种情况下,第一个构造函数在重载决议中获胜?