下面是模板化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_*
重载,请注意,由于是模板,转发/模板版本的优先级较低。选择权在你。