我正在为一个机器学习库编写一些模板化的类,我很多时候都面临这个问题.我主要使用策略模式,其中类接收作为不同功能的模板参数策略,例如:
template <class Loss, class Optimizer> class LinearClassifier { ... }
Run Code Online (Sandbox Code Playgroud)
问题在于构造函数.随着策略量(模板参数)的增长,const引用和右值引用的组合呈指数级增长.在前面的示例中:
LinearClassifier(const Loss& loss, const Optimizer& optimizer) : _loss(loss), _optimizer(optimizer) {}
LinearClassifier(Loss&& loss, const Optimizer& optimizer) : _loss(std::move(loss)), _optimizer(optimizer) {}
LinearClassifier(const Loss& loss, Optimizer&& optimizer) : _loss(loss), _optimizer(std::move(optimizer)) {}
LinearClassifier(Loss&& loss, Optimizer&& optimizer) : _loss(std::move(loss)), _optimizer(std::move(optimizer)) {}
Run Code Online (Sandbox Code Playgroud)
有没有办法避免这种情况?
我想知道一个右值引用成员有什么用
class A {
// ...
// Is this one useful?
Foo &&f;
};
Run Code Online (Sandbox Code Playgroud)
与左值参考成员相比,它有任何好处或缺点吗?什么是它的主要用途?
当我正在阅读boost/shared_ptr.hpp时,我看到了这段代码:
// generated copy constructor, destructor are fine...
#if defined( BOOST_HAS_RVALUE_REFS )
// ... except in C++0x, move disables the implicit copy
shared_ptr( shared_ptr const & r ): px( r.px ), pn( r.pn ) // never throws
{
}
#endif
Run Code Online (Sandbox Code Playgroud)
注释"生成复制构造函数,析构函数是否正常,除了在C++ 11中,移动禁用隐式副本"是什么意思?我们是否总是自己编写副本来防止C++ 11中出现这种情况?
因此,在查找移动语义之后,我发现当您打算转移所有权时,普遍的共识是通过值传递.但在Scott Meyer关于Universal引用的讨论中,我注意到std::vector::push_back有2个重载:
void push_back( const T& value );
void push_back( T&& value );
Run Code Online (Sandbox Code Playgroud)
所以我心想,void push_back( T value );不够吗?我问了一些最终导致以下测试用例的人:
#include <memory>
#include <iostream>
#include <type_traits>
struct A
{
A() { std::cout << "A Default constructor\n"; }
A(const A &) { std::cout << "A Copy\n"; }
A(A &&) { std::cout << "A Move\n"; }
};
std::aligned_storage<sizeof(A)> contents;
A& alias = *reinterpret_cast<A*>(&contents);
void ByVal(A a)
{
new (&contents) A(std::move(a));
alias.~A();
}
void ByLCRef(A const& a)
{
new …Run Code Online (Sandbox Code Playgroud) 根据en.cppreference.com(据我所知):
std::is_convertible被性状类需要类型From&To为使得与返回类型的函数To返回一个From值可以通过编译。std::convertible_to是一个概念,要求类型From&To如上所述,AND使得类型的r 值引用From可以转换为static_cast<To>。强加的要求std::is_convertible似乎相对简单。相反,对于 C++20 特性的简单示例中显示的这种通用概念,r 值引用转换要求std::convertible_to似乎奇怪地特定。
作为 C++ 的新手,我无法完全理解两个网页中提供的一些术语和部分补充说明,我无法想象两者的要求之间的确切区别。
一些相互关联的问题:
From& Toof 不仅受到std::is_convertible奇怪的 r 值引用转换要求的约束,而且受到奇怪的 r 值引用转换要求的实际影响是什么?From和To被附加由R值参考铸件的要求被拒绝?std::is_convertible或std::convertible_to中的一个而不是另一个作为其函数返回类型或参数类型的约束(除了概念的便利性)?一个更简单的解释或一个例子会有所帮助。谢谢!
§3.10第9节说"非类别rvalues总是有cv不合格类型".这让我很奇怪......
int foo()
{
return 5;
}
const int bar()
{
return 5;
}
void pass_int(int&& i)
{
std::cout << "rvalue\n";
}
void pass_int(const int&& i)
{
std::cout << "const rvalue\n";
}
int main()
{
pass_int(foo()); // prints "rvalue"
pass_int(bar()); // prints "const rvalue"
}
Run Code Online (Sandbox Code Playgroud)
根据标准,对于非类型类型没有const rvalue,但bar()更喜欢绑定const int&&.这是编译器错误吗?
编辑:显然,this也是一个const rvalue :)
编辑:这个问题似乎在g ++ 4.5.0中得到修复,现在两行打印"rvalue".
在一些地方,我已经看到了复制和移动构造函数的推荐签名,如下所示:
struct T
{
T();
T(const T& other);
T(T&& other);
};
Run Code Online (Sandbox Code Playgroud)
复制构造函数采用const引用,移动构造函数采用非const rvalue引用.
据我所知,这使我无法在从函数返回const对象时利用移动语义,例如下面的情况:
T generate_t()
{
const T t;
return t;
}
Run Code Online (Sandbox Code Playgroud)
使用VC11 Beta进行测试,T调用复制构造函数,而不是移动构造函数.即使使用return std::move(t);复制构造函数仍然被调用.
我可以看到这是有道理的,因为tconst是不应该绑定的T&&.使用const T&&在移动构造函数签名工作正常,并且是有道理的,但你必须是因为这个问题other是常量,你不能将它的会员空出来,如果他们需要被清零了-当所有的成员都标量它只会工作或者使用正确的签名移动构造函数.
它看起来是确保在一般情况下调用移动构造t函数以便首先创建非const 的唯一方法,但我不喜欢这样做 - 构造事物是好的形式,我不希望客户T要知道他们必须反对这种形式才能提高性能.
所以,我想我的问题是双重的; 首先,移动构造函数应该采用const还是非const rvalue引用?第二:我在这种推理中是对的吗?我应该停止返回const的东西?
我正在编写一个网络库,并大量使用移动语义来处理文件描述符的所有权.我的一个类希望接收其他类型的文件描述符包装并取得所有权,所以就像这样
struct OwnershipReceiver
{
template <typename T>
void receive_ownership(T&& t)
{
// taking file descriptor of t, and clear t
}
};
Run Code Online (Sandbox Code Playgroud)
它必须处理多个不相关的类型,所以receive_ownership必须是一个模板,为了安全起见,我希望它只绑定到右值引用,这样用户在传递左值时必须显式地声明std :: move.
receive_ownership(std::move(some_lvalue));
但问题是:C++模板推导允许在没有额外努力的情况下传递左值.我实际上是因为不小心将左值传递给receive_ownership并且稍后使用了左值(清除)而将自己击中一只脚.
所以这是一个问题:如何使模板仅绑定到右值参考?
#include <set>
#include <string>
#include <cassert>
using namespace std::literals;
int main()
{
auto coll = std::set{ "hello"s };
auto s = "hello"s;
coll.insert(std::move(s));
assert("hello"s == s); // Always OK?
}
Run Code Online (Sandbox Code Playgroud)
C ++标准是否保证插入关联容器失败不会修改rvalue-reference参数?
c++ stl rvalue-reference language-lawyer pass-by-rvalue-reference
我一直假设std::move()a上会std::shared_ptr窃取指针并将原始指针设置为nullptr-从而不增加引用计数。在我的世界中似乎并非如此。
设置:
MacOS,g ++ -version =>“ Apple LLVM版本10.0.1(clang-1001.0.46.3)”
代码:
#include <cstdio>
#include <memory>
class Thing { public: Thing(int N) : value(N) {} int value; };
void print(const char* name, std::shared_ptr<Thing>& sp)
{ printf("%s: { use_count=%i; }\n", name, (int)sp.use_count()); }
int main(int argc, char** argv) {
std::shared_ptr<Thing> x(new Thing(4711));
print("BEFORE x", x);
std::shared_ptr<Thing> y = std::move(x);
y->value = 4712;
print(" AFTER x", x);
print(" AFTER y", y);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
编译( …
c++ ×10
rvalue-reference ×10
c++11 ×6
stl ×2
boost ×1
c++-concepts ×1
c++20 ×1
macos ×1
rvalue ×1
shared-ptr ×1