没有模板能不能完美转发
Can you perfectly forward without templates
我有一个 class 有多个构造函数:
class Obj
{
public:
Obj(int x, int y) {}
Obj(std::string const& str) {}
Obj(char v, int s) {}
};
现在我想向存储在对象中的构造函数添加一个选项对象。但是为了使这项工作顺利进行,我想尽可能地移动选项,但在必须时复制。看来我必须将构造函数的数量加倍才能支持选项的移动和复制。
class Options {};
class Obj
{
Options options;
public:
Obj(Options const& o, int x, int y): options(o) {}
Obj(Options const& o, std::string const& str):options(o) {}
Obj(Options const& o, char v, int s) :options(o) {}
Obj(Options&& o, int x, int y): options(std::move(o)) {}
Obj(Options&& o, std::string const& str):options(std::move(o)) {}
Obj(Options&& o, char v, int s) :options(std::move(o)) {}
};
如果我使用了模板,我就可以使用完美转发并获得正确的效果。
template<typename Options>
class Obj
{
Options options;
public:
Obj(Options&& o, int x, int y): options(std::forward<Options>(o)) {}
Obj(Options&& o, std::string const& str):options(std::forward<Options>(o)) {}
Obj(Options&& o, char v, int s) :options(std::forward<Options>(o)) {}
};
问题在于我知道类型 Options
。
转发引用仅适用于模板,您可以将构造函数模板化并对模板参数施加限制。
class Obj
{
Options options;
template<typename Opt>
using ValidOption = std::enable_if_t<std::is_same_v<Options, std::decay_t<Opt>>, bool>;
public:
template <typename X = Options, ValidOption<X> = true>
Obj(X&& o, int x, int y): options(std::forward<Options>(o)) {}
template <typename X = Options, ValidOption<X> = true>
Obj(X&& o, std::string const& str):options(std::forward<Options>(o)) {}
template <typename X = Options, ValidOption<X> = true>
Obj(X&& o, char v, int s) :options(std::forward<Options>(o)) {}
};
你的最后一个片段:
template <typename Options>
class Obj
{
Options options;
public:
Obj(Options&& o, int, int): options(std::forward<Options>(o)) {}
Obj(Options&& o, std::string const&) : options(std::forward<Options>(o)) {}
Obj(Options&& o, char, int) : options(std::forward<Options>(o)) {}
};
不是完美的转发,因为它是你的 class 这是模板,而不是你的函数。
完美转发为:
class Obj
{
Options options;
public:
template <typename T> Obj(T&& o, int, int): options(std::forward<T>(o)) {}
template <typename T> Obj(T&& o, std::string const&) : options(std::forward<T>(o)) {}
template <typename T> Obj(T&& o, char, int) : options(std::forward<T>(o)) {}
};
我在 Taking sink parameters by rvalue reference instead of by value to enforce performant usage of interfaces
中总结了(性能)选项
所以除非性能真的很重要,甚至额外的移动也很重要,否则我会选择
Obj(Options o, int x, int y) : options(std::move(o)) {}
或
Obj(Options&& o, int x, int y) : options(std::move(o)) {}
(取决于您希望避免隐式复制的重要性)。
如果你的目标是性能,你确实需要转发参考。
我有一个 class 有多个构造函数:
class Obj
{
public:
Obj(int x, int y) {}
Obj(std::string const& str) {}
Obj(char v, int s) {}
};
现在我想向存储在对象中的构造函数添加一个选项对象。但是为了使这项工作顺利进行,我想尽可能地移动选项,但在必须时复制。看来我必须将构造函数的数量加倍才能支持选项的移动和复制。
class Options {};
class Obj
{
Options options;
public:
Obj(Options const& o, int x, int y): options(o) {}
Obj(Options const& o, std::string const& str):options(o) {}
Obj(Options const& o, char v, int s) :options(o) {}
Obj(Options&& o, int x, int y): options(std::move(o)) {}
Obj(Options&& o, std::string const& str):options(std::move(o)) {}
Obj(Options&& o, char v, int s) :options(std::move(o)) {}
};
如果我使用了模板,我就可以使用完美转发并获得正确的效果。
template<typename Options>
class Obj
{
Options options;
public:
Obj(Options&& o, int x, int y): options(std::forward<Options>(o)) {}
Obj(Options&& o, std::string const& str):options(std::forward<Options>(o)) {}
Obj(Options&& o, char v, int s) :options(std::forward<Options>(o)) {}
};
问题在于我知道类型 Options
。
转发引用仅适用于模板,您可以将构造函数模板化并对模板参数施加限制。
class Obj
{
Options options;
template<typename Opt>
using ValidOption = std::enable_if_t<std::is_same_v<Options, std::decay_t<Opt>>, bool>;
public:
template <typename X = Options, ValidOption<X> = true>
Obj(X&& o, int x, int y): options(std::forward<Options>(o)) {}
template <typename X = Options, ValidOption<X> = true>
Obj(X&& o, std::string const& str):options(std::forward<Options>(o)) {}
template <typename X = Options, ValidOption<X> = true>
Obj(X&& o, char v, int s) :options(std::forward<Options>(o)) {}
};
你的最后一个片段:
template <typename Options>
class Obj
{
Options options;
public:
Obj(Options&& o, int, int): options(std::forward<Options>(o)) {}
Obj(Options&& o, std::string const&) : options(std::forward<Options>(o)) {}
Obj(Options&& o, char, int) : options(std::forward<Options>(o)) {}
};
不是完美的转发,因为它是你的 class 这是模板,而不是你的函数。
完美转发为:
class Obj
{
Options options;
public:
template <typename T> Obj(T&& o, int, int): options(std::forward<T>(o)) {}
template <typename T> Obj(T&& o, std::string const&) : options(std::forward<T>(o)) {}
template <typename T> Obj(T&& o, char, int) : options(std::forward<T>(o)) {}
};
我在 Taking sink parameters by rvalue reference instead of by value to enforce performant usage of interfaces
中总结了(性能)选项所以除非性能真的很重要,甚至额外的移动也很重要,否则我会选择
Obj(Options o, int x, int y) : options(std::move(o)) {}
或
Obj(Options&& o, int x, int y) : options(std::move(o)) {}
(取决于您希望避免隐式复制的重要性)。
如果你的目标是性能,你确实需要转发参考。