我正在编写一个基本的类模板,它需要两种参数类型。该类的思想是将一种类型作为
目前,这是我的当前类,只有基本类型,但计划通过可变构造扩展到任何2种类型。
无论我如何使用
这在Visual Studio 2017中会导致编译错误,无论是哪种情况。
或者在展开之后……
const ref
输入,将另一种类型作为ref
输入。该类的功能是将类型A
转换为类型B
,其中创建的对象最终将成为b
。我希望在这个类模板中使用perfect-forwarding
或move semantics
。
目前,这是我的当前类,只有基本类型,但计划通过可变构造扩展到任何2种类型。
#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::move
或 std::forward
来声明上面的构造函数,这个类都可以编译通过。现在当我包含它并尝试调用其构造函数来实例化一个对象时... 如果我这样做:int i = 10;
float f = 0;
Converter<int, float> converter( i, f );
这在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 ==========
这是可以理解的 {无法将左值绑定到右值引用
}。
然而,如果我尝试像这样使用构造函数:
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::move
或std::forward
,那么在实例化模板类对象时为什么还要再次使用它们?这不会被认为是多余的吗?如果是,那么构造函数应该如何设计,以便用户在调用此构造函数时不必使用std::move()
或std::forward<T>()
?- 在这个上下文中,将
A
转换为B
的最普遍和类型安全的方法是什么?- 一旦上述两个问题得到明确的回答,那么在这个上下文中,对于上述标准类或其他类似类型的实现
operator()()
将是什么样子?
关于上述三个相关问题的解答,我的最终想法是,在设计过程的某个时刻,我曾考虑使用std::any
及其相关函数作为其实现过程的一部分。我不知道std::any
是否可以在这种情况下使用,如果可以,它应该如何使用?
编辑
以下可能是这个类未来的一些合理用途:
vector<int> vecFrom{1,2,3, ...};
set<int> setTo;
Converter<vector<int>, set<int>> converter( vecFrom, setTo );
或者在展开之后……
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 );
T&&
才是一个转发引用。从您的代码Converter<int, float> converter(i, f)
可以看出,没有进行类型推导,因此这两个参数最终成为右值引用。 - Mário Feroldistd::move
是这种情况下更好的选择。std::forward
的目的是与推导出的模板参数一起使用。 - M.M模板参数
,那么forward
就是过度使用了,而move
则是合适的...我想我开始理解两者之间的总体差异概念了。 - Francis Cugler