我想完美转发,但我已经知道(并且只接受)我的功能将采用的类型。
以下是我输入的一个简单示例:
class big_class
{
private:
std::string m_somethingBig;
};
class testmove
{
public:
void Add(big_class&& big)
{
std::cout << "Add via move\n";
m_bigClasses.push_back(std::move(big));
}
void Add(big_class const& big)
{
std::cout << "Add via copy\n";
m_bigClasses.push_back(big);
}
private:
std::vector<big_class> m_bigClasses;
};
int main()
{
testmove tm;
big_class big;
tm.Add(big);
tm.Add(big_class{});
}
是否可以在testmove::Add()
的两个重载之间进行某种形式的实现共享?我想优化移动,如果有人在没有我的右值超载的情况下std::move()
,它会在添加到我的向量之前至少做一个副本。
同样,我意识到我可以通过使Add()成为模板函数,甚至使用类型特征和一些模板技巧来解决这个问题。但是如果可能的话我想避免这种情况。如果您需要知道原因,我有几个原因:
big_class
)。答案 0 :(得分:2)
Xeo建议的方法(按参数取值)是我强烈推荐的方法。但是,如果由于某种原因你不能这样做(例如,移动费用昂贵但比副本少),请继续阅读。
我认为可以满足您的所有标准,但如果代码足够复杂以至于重复它会很糟糕,那么它是值得的。我们的想法是委托一个模板,该模板将仅为big_class
显式实例化。
big_class.h
:
// ...
public:
void Add(big_class&& big)
{
Add_internal(std::move(big));
}
void Add(big_class const& big)
{
Add_internal(big);
}
private:
// not part of interface; defined in .cpp file
template <typename T> void Add_internal(T&& big);
big_class.cpp
:
// implementation of template
template <typename T> void big_class::Add_internal(T&& big) {
// shared logic goes here
m_bigClasses.push_back(std::forward<T>(big));
}
// explicit instantiation
template void big_class::Add_internal<big_class>(big_class&&);
template void big_class::Add_internal<big_class const&>(big_class const&);
答案 1 :(得分:1)
如果您真的无法忍受按值添加的想法,您可以提供一个内部模板化的impl:
private:
template<class X>
auto add_impl(X&& x) {
m_bigClasses.push_back(std::forward<X>(x));
}
public:
void Add(big_class&& big)
{
std::cout << "Add via move\n";
add_impl(std::move(big));
}
void Add(big_class const& big)
{
std::cout << "Add via copy\n";
add_impl(std::move(big));
}
这怎么办?你正在移动一个常规参考!
因为std::move
没有移动任何东西。它只是将一个l值引用转换为r值引用。因此const T&
成为const T&&
,没有人编码。因此它会衰减以匹配人们为其编码的const T&
或T
。