没有模板能不能完美转发

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)) {}

(取决于您希望避免隐式复制的重要性)。

如果你的目标是性能,你确实需要转发参考。