应该优先考虑什么,移动或转发论点



下面是模板化List的简化示例,其中有两个具有相同目标的append_move()append_forward()函数,使用参数并将它们放置到容器List中。第一个append_move()函数获取传递的值arg1,然后将其移动到emplace_back()函数。第二个append_move()函数使用arg1的自动推导,然后将其转发给emplace_back()函数。

append_forward()功能与append_move()功能相比有什么优势吗?应该优先选择哪个功能?

#include <deque>
#include <string>
#include <utility>
template<typename T>
class List
{
public:
void append_move(T arg1, std::string arg2)
{
list.emplace_back(std::move(arg1), std::move(arg2));
}
template<typename X>
void append_forward(X&& arg1, std::string arg2)
{
list.emplace_back(std::forward<X>(arg1), std::move(arg2));
}
private:
std::deque<std::pair<T, std::string>> list;
};

前进或移动

如果T的析构函数不能被优化并产生明显的副作用,例如

struct Loud { ~Loud() { std::cout << "destructorn"; } };

然后

List<Loud> list;
Loud const loud;
list.append_forward(loud);

比少调用一个析构函数

list.append_move(loud);

因为后者构造了另一个对象=>必须再调用一个析构函数。因此,转发更可取。

然而,它使API不那么漂亮:

another_list.append_move({"some", "arguments"}); // works and pretty
//another_list.append_forward({"some", "arguments"}); // doesn't compile
another_list.append_forward(Foo{"some", "arguments"}); // works

手动过载

因此,不幸的是,提供手写重载似乎是这三种解决方案中最好的(对代码用户来说(:

void append_overload(T&& t); // TODO actually implement
void append_overload(T const& t) { append_overload(T{t}); }

就业

然而(再次(,如果你关心所有这些,请考虑放置:

template<typename... As> void append_emplace(As&&... args) {
list.emplace_back(std::forward<As>(args)...);
}
// works and pretty as long as you don't need to pass-construct two arguments
another_list.append_emplace("some", "arguments");

其他过载

此外,如果您有更多的append_*重载,请注意,由于是模板,转发/模板版本的优先级较低。选择权在你。

相关内容

  • 没有找到相关文章

最新更新