试图理解std :: forward,std :: move更好一点

Fra*_*ler 8 c++ templates std move-semantics perfect-forwarding

我正在编写一个基本的类模板.它的参数需要两种参数类型.该类的想法是将一种类型作为a const ref和另一种作为a ref.该类的功能是将类型转换为创建对象最终的A类型.我想有或该类模板的有效组成部分.Bbperfect-forwardingmove semantics


现在这里是我目前只有基本类型的类,但计划使用可变参数构造将其扩展为任何两种类型.

#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
Run Code Online (Sandbox Code Playgroud)

无论哪种方式,我都声明上面的构造函数std::move或者std::forward这个类自己编译.现在,当我包含它并尝试在调用其构造函数之前实例化一个对象...如果我这样做:

int i = 10;
float f = 0;  
Converter<int, float> converter( i, f );
Run Code Online (Sandbox Code Playgroud)

这在两种情况下都会在Visual Studio 2017中给出编译器错误.

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 ==========
Run Code Online (Sandbox Code Playgroud)

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


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

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 ) );
Run Code Online (Sandbox Code Playgroud)

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


为了更好地理解它显然似乎std::move(...)std::forward<T>(...)几乎可以互换并做同样的事情,除了std::forward<T>(...)有额外的演员参与.


现在,因为我只显示基本类型,所以它看起来更合理使用std::move,但是我最终可能想要使用更复杂的类型,所以我想提前设计这个想法,所以我我倾向于std::forward<T>完美的转发.


有了这个,并完成这个课程,有3个问题耦合在一起.

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

为了完成上述3个耦合问题,最后我想到的是,在设计过程的某个时刻,我曾考虑过将std::any其使用及其相关功能作为其实施过程的一个可能部分.我不知道是否std::any可以在这种情况下使用,如果是这样的话怎么样?


编辑

这个类可能有以下几种可能的用途:

vector<int> vecFrom{1,2,3, ...};
set<int>    setTo;

Converter<vector<int>, set<int>> converter( vecFrom, setTo );
Run Code Online (Sandbox Code Playgroud)

或扩大后......

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 );
Run Code Online (Sandbox Code Playgroud)

小智 4

这里有很多问题对我来说似乎无法简洁地回答,但有一个问题很突出:

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

std::move 用于将左值引用转换为右值引用,通常是将一个左值持有的资源转移到另一个左值。

std::forward 用于区分左值引用和右值引用,通常在右值引用类型的参数被推导为左值的情况下。

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

有关更多详细信息,我发现以下内容很有帮助:http://thbecker.net/articles/rvalue_references/section_01.html