首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >试着理解std::前进,std:移动得更好一点

试着理解std::前进,std:移动得更好一点
EN

Stack Overflow用户
提问于 2018-01-26 01:27:47
回答 1查看 1.1K关注 0票数 9

我正在编写一个基本的类模板。它的参数采用两种参数类型。类的思想是将一种类型作为const ref,另一种类型作为ref。类的功能是将类型A转换为B类型,创建的对象最终将是b。我希望perfect-forwardingmove semantics是这个类模板的有效部分。

现在,这里是我的当前类,它只包含基本类型,但计划通过使用各种构造将其扩展到任何2种类型。

代码语言:javascript
复制
#ifndef CONVERTER_H
#define CONVERTER_H

#include <utility>

template<class From, class To>
class Converter {
private:
    From in_;
    To   out_;

public:
    // Would like for From in to be a const (non modifiable) object
    // passed in by perfect forwarding or move semantics and for 
    // To out to be returned by reference with perfect forwarding 
    // or move semantics. Possible Constructor Declarations - Definitions

    // Using std::move
    Converter( From&& in, To&& out ) :
        in_{ std::move( in ) },
        out_{ std::move( out ) } 
    {
        // Code to convert in to out
    }

    // Or using std::forward
    Converter( From&& in, To&& out ) :
        in_{ std::forward<From>( in ) },
        out_{ std::forward<To>( out ) } {

        // Code to convert in to out.
     }        

    // Pseudo operator()... 
    To operator()() {
        return out_;
    }
};

#endif // !CONVERTER_H

无论以哪种方式,我用std::movestd::forward来声明上面的构造函数,这个类都是自己编译的。现在,当我包括这个,并尝试实例化一个对象以上调用它的构造函数.如果我这么做:

代码语言:javascript
复制
int i = 10;
float f = 0;  
Converter<int, float> converter( i, f );

在这两种情况下,Visual 2017都会出现编译器错误。

代码语言:javascript
复制
1>------ Build started: Project: ExceptionManager, Configuration: Debug Win32 ------
1>main.cpp
1>c:\users\skilz80\documents\visual studio 2017\projects\exceptionmanager\exceptionmanager\main.cpp(54): error C2664: 'Converter<unsigned int,float>::Converter(Converter<unsigned int,float> &&)': cannot convert argument 1 from 'unsigned int' to 'unsigned int &&'
1>c:\users\skilz80\documents\visual studio 2017\projects\exceptionmanager\exceptionmanager\main.cpp(54): note: You cannot bind an lvalue to an rvalue reference
1>Done building project "ExceptionManager.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

这是可以理解的{can't bind lvaule to rvalue ref}。

但是,如果我尝试像这样使用构造函数:

代码语言:javascript
复制
int i = 10;
float f = 0;
Converter<int,float> converter( std::move( i ), std::move( f ) );

// Or
Converter<int,float> converter( std::forward<int>( i ), std::forward<float>( f ) );

它编译和构建,不管std::move(...)std::forward<T>(...)是否在类中使用。

据我更好的理解,很明显,std::move(...) & std::forward<T>(...)几乎是可以互换的,并且做同样的事情,除了std::forward<T>(...)有额外的演员。

现在,由于我只展示了基本类型,所以使用std::move似乎更合理,但是我最终可能希望使用更复杂的类型,因此我希望提前设计它,考虑到这一点,所以我倾向于使用std::forward<T>来实现完美的转发。

说到这里,为了完成这门课,有三个问题结合在一起。

  • 如果我在类的构造函数的成员初始化列表中使用std::movestd::forward,为什么在实例化模板类对象时必须再次使用它们;这难道不被认为是多余的吗?如果是这样的话,构造函数的外观将如何,以便用户在调用此构造函数时不必使用std::move()std::forward<T>()
  • 在这种情况下,将A转换为B的最普遍和最安全的方法是什么?
  • 一旦清楚地回答了上述两个问题,那么在这个上下文中使用上述标准类或其他类似类型的最后一部分将是关于实现operator()()的内容,对于上面已经提到的内容,它会是什么样子呢?

为了完成以上三个耦合问题的处理,我最后的想法是,在设计过程的某一时刻,我曾经考虑过使用std::any及其相关功能作为其实现过程的一个可能部分。我不知道在这个上下文中是否可以使用std::any,如果可以,如何使用?

编辑

以下是这个类的几种可能的未来用途:

代码语言:javascript
复制
vector<int> vecFrom{1,2,3, ...};
set<int>    setTo;

Converter<vector<int>, set<int>> converter( vecFrom, setTo );

或者在扩张之后。

代码语言:javascript
复制
vector<int>     vecIntFrom{1,2,3, ...};
vector<string>  vecStringFrom{ "a", "b", "c", ... };
map<int,string> mapTo;
Converter<vector<int>, vector<string>, map<int,string> converter( vecIntFrom, vecStringFrom, mapTo );
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-03-20 01:06:15

这里有许多问题,我似乎不太清楚地回答,但有一个问题很突出:

“std::move和std::forward有什么区别?”

移动用于将lvalue引用转换为rvalue引用,通常用于将一个lvalue所持有的资源转移到另一个。

forward用于区分lvalue和rvalue引用,通常是在将rvalue引用类型的参数推断为lvalue的情况下。

结果:如果要根据传递时对象的引用类型进行分支,请使用std::forward。如果您只想通过转换为rvalue来窃取lvalue的资源,请使用std::move。

有关更多细节,我发现以下内容很有帮助:01.html

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48454577

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档