![](/img/trans.png)
[英]std::initializer_list as constructor argument in template class
[英]std::move in constructor initializer list in class template
我有这样的模板:
template<typename T>
struct foo {
T m_t;
foo(T t) : m_t(t) {}
};
问题是,我想支持小/普通类型和巨大的类型(如矩阵)的T
。 您是否建议我像这样编写构造函数初始化列表
foo (T t) : m_t(std::move(t)) {}
并要求T
型始终支持移动结构,即使是较小的类型? 还有更好的方法吗?
并要求T型始终支持移动结构,即使是较小的类型?
任何可复制构造的类型也可移动构造。 在这些情况下移动只需调用复制构造函数。 因此,没有理由不使用m_t(std::move(t))
。
另一种方法是使用引用:
foo (T const& t) : m_t(t) {}
foo (T&& t) : m_t(std::move(t)) {}
这样做的好处是只涉及一种结构而不是两种结构。
是的,在这种情况下使用此举并没有不利之处。 所有可复制对象都可以自动移动,因此无关紧要。 事实上,有些人建议在可能的情况下始终移动变量,甚至是整数。
作为替代方案,您可以考虑使用完美转发,如本答案中所述 :
template <typename T2>
foo(T2&& t) : m_t(std::forward<T2>(t)) {}
如果你知道T
定义了一个快速移动构造函数,那应该没关系。 否则,建议提供构造函数foo(const T&)
以避免不必要的副本。
完美转发只是实现这一目标的一种技术。 Pubby写出构造函数foo(const T&)
和foo(T&&)
的解决方案当然也没问题。 结果是一样的,它主要是风格问题。
您还询问了小整数类型。 理论上,通过引用传递它们比复制它们要慢,但无论如何编译器应该能够将它优化为副本。 我不认为它会有所作为。
因此,更好地优化T
可能很大并且不提供快速移动构造函数的最坏情况。 通过引用传递最适合这种情况,并且通常也不应该是一个糟糕的选择。
通过值传递的优点是只有一个构造函数(没有模板),但与上述替代方案相比,其代价是一个额外的移动构造。
但是,Pubby给出了pass-by-value和非模板解决方案的另一个未提及的缺点:如果复制构造函数定义为T(T&);
则移动将不起作用T(T&);
(注意对非const的引用)。 Rvalue-references可以绑定到lvalue-references-to-const,但不能绑定到lvalue-references-to-non-const,因此编译器无法调用复制构造函数。
要解决此问题,您只需向Pubby的解决方案添加第三个重载foo (T & t) : m_t(t) {}
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.