std::类中的正向和右值引用



我一直在阅读std::forward,我认为我很了解它,但我认为我对它的了解还不够熟练地使用它。

我有一个模板类,它实现了一个容器,并有一个名为insert的方法。我希望这个方法接受常量引用和右值引用,这样如果插入的元素是右值引用,它就会被移动到容器中,而不是复制。为此,我首先这样重载insert方法:

template <typename U>
void do_some_work(U&& x) noexcept
{
m_data = std::forward<U>(x);
}
void insert(const T& x) 
{
do_some_work(x);
}
void insert(T&& x) {
do_some_work(std::forward<T>(x);
}

问题是,这两个函数现在必须调用一个"inner"实现断言的函数。如果函数很小,我想这不是问题,但如果函数很大,最好使用模板,就像这样

template <typename U>
void insert(U&& x) 
{
do_some_work(std::forward<U>(x);
}

问题1这是正确的吗?


现在,我想做同样的事情,但与std::vector

void insert_vector(const std::vector<T>& v) noexcept {
for (std::size_t i = 0; i < v.size(); ++i) {
do_some_work(v[i]);
}
}
void insert_vector(std::vector<T>&& v) noexcept 
{
for (std::size_t i = 0; i < v.size(); ++i) 
{
do_some_work(std::forward<T>(v[i]));
}
}

问题2:我如何将insert_vector函数折叠成单个函数,以便使用

完成对do_some_work的调用
  • 当vector是右值引用(例如用std::move指定)时,
  • 常量引用,当vector不是作为右值引用给出时,如下面MWE的(4)
template <typename U>
void insert_vector(U&& v) noexcept 
{
for (std::size_t i = 0; i < v.size(); ++i) 
{
do_some_work(std::forward<T>(v[i]));
}
}

这里是一个最小的工作示例:

#include <iostream>
#include <vector>
template <typename T>
class my_class 
{
private:
T m_data;
private:
template <typename U>
void do_some_more_work(U&& x) noexcept {
m_data = std::forward<U>(x);
}
template <typename U>
void do_some_work(U&& x) noexcept {
do_some_more_work(std::forward<U>(x));
}
public:
void insert(const T& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
do_some_work(x);
}
void insert(T&& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
do_some_work(std::forward<T>(x));
}
void insert_vector(const std::vector<T>& v) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
for (std::size_t i = 0; i < v.size(); ++i) {
do_some_work(v[i]);
}
}
void insert_vector(std::vector<T>&& v) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
for (std::size_t i = 0; i < v.size(); ++i) {
do_some_work(std::forward<T>(v[i]));
}
}
};
struct my_struct {
my_struct() noexcept = default;
my_struct(int v) noexcept : m_v(v) { }
my_struct(const my_struct& s) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
m_v = s.m_v;
}
my_struct(my_struct&& s) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
m_v = std::move(s.m_v); // not need, but whatever
s.m_v = -1;
}
my_struct& operator= (const my_struct& s) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
m_v = s.m_v;
return *this;
}
my_struct& operator= (my_struct&& s) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
m_v = std::move(s.m_v); // not need, but whatever
s.m_v = -1;
return *this;
}
int m_v;
};
int main() {
my_class<my_struct> mc;
std::cout << "===========================================n";
{
std::cout << "-------------------------------------------n";
std::cout << "(1.1)n";
my_struct s{3};
std::cout << s.m_v << 'n';
mc.insert(s);
std::cout << s.m_v << 'n';
}
{
std::cout << "-------------------------------------------n";
std::cout << "(1.2)n";
const my_struct s{3};
std::cout << s.m_v << 'n';
mc.insert(s);
std::cout << s.m_v << 'n';
}
std::cout << "===========================================n";
{
std::cout << "-------------------------------------------n";
std::cout << "(2.1)n";
mc.insert(my_struct{5});
}
{
std::cout << "-------------------------------------------n";
std::cout << "(2.2)n";
my_struct s{5};
std::cout << s.m_v << 'n';
mc.insert(std::move(s));
std::cout << s.m_v << 'n';
}
std::cout << "===========================================n";
{
std::cout << "-------------------------------------------n";
std::cout << "(3.1)n";
std::vector<my_struct> v(5);
for (std::size_t i = 0; i < v.size(); ++i) { v[i] = my_struct(i); }
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << 'n';
mc.insert_vector(v);
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << 'n';
}
{
std::cout << "-------------------------------------------n";
std::cout << "(3.2)n";
const std::vector<my_struct> v = []() {
std::vector<my_struct> v(5);
for (std::size_t i = 0; i < v.size(); ++i) { v[i] = my_struct(i); }
return v;
}();
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << 'n';
mc.insert_vector(v);
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << 'n';
}
std::cout << "===========================================n";
{
std::cout << "-------------------------------------------n";
std::cout << "(4)n";
std::vector<my_struct> v(5);
for (std::size_t i = 0; i < v.size(); ++i) { v[i] = my_struct(i); }
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << 'n';
mc.insert_vector(std::move(v));
for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << 'n';
}
}

我想我找到了解决这个问题的方法。我用了同样的"技巧"。与常规insert方法一样。my_class的完整实现是这样的。不幸的是,我不能创建一个insert方法。

template <typename T>
class my_class {
private:
T m_data;
private:
template <typename U>
void do_some_more_work(U&& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
m_data = std::forward<U>(x);
}
template <typename U>
void do_some_work(U&& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
do_some_more_work(std::forward<U>(x));
}
public:
template <typename U>
void insert(U&& x) noexcept {
std::cout << __PRETTY_FUNCTION__ << 'n';
do_some_work(std::forward<U>(x));
}
template <typename U>
void insert_vector(U&& v) noexcept {
using elem_t = typename std::remove_reference_t<U>::value_type;
// this is used here for testing purposes.
static_assert(std::is_same_v<elem_t, my_struct>);
std::cout << __PRETTY_FUNCTION__ << 'n';
for (std::size_t i = 0; i < v.size(); ++i) {
if constexpr (std::is_same_v<std::vector<elem_t>, U>) {
do_some_work(std::forward<T>(v[i]));
}
else {
do_some_work(v[i]);
}
}
}

};

最新更新