完美转发到数据成员的成员函数?

时间:2014-03-02 18:09:52

标签: c++ member auto forwarding c++14

考虑一个具有private std::vector数据成员的类:

class MyClass 
{
    private: 
        std::vector<double> _data;
    public:
        template <class... Args>
        /* something */ insert(Args&&... args) /* something */
        {
            return _data.insert(std::forward<Args>(args)...);
        }
};

_data的给定函数传递给MyClass的正确语法(使用C ++ 14 auto / variadic templates / forward ...)是什么(例如insert )并为用户提供相同的界面?

2 个答案:

答案 0 :(得分:6)

正确的语法是:

class MyClass 
{
    private: 
        std::vector<double> _data;
    public:
        template <class... Args>
        decltype(auto) insert(Args&&... args)
        {
            return _data.insert(std::forward<Args>(args)...);
        }
};

但是,实际上并不需要C ++ 14来实现它。您可以使用C ++ 11语法。

class MyClass 
{
    private: 
        std::vector<double> _data;
    public:
        template <class... Args>
        auto insert(Args&&... args) 
        -> decltype(_data.insert(std::forward<Args>(args)...))
        {
            return _data.insert(std::forward<Args>(args)...);
        }
};

答案 1 :(得分:2)

真正转发对成员函数的调用,必须考虑正确转发成员调用的*this值的必要性。

以下内容:

template<typename Type>
struct Fwd {
    Type member;

    template<typename ...Args>
    decltype(auto) Func(Args&&... args)
        noexcept(noexcept(member.Func(std::forward<Args>(args)...)))
        { return member.Func(std::forward<Args>(args)...); }
};

足以转发参数和异常规范,正如您可能已经猜到的那样。但这不足以完善前进*this

struct S {
    // These overloads are reachable through Fwd<S>::Func().
    void Func(int) & {}
    void Func(int&&) & {}

    // These other overloads are not.
    void Func(int) const&;
    void Func(int&&) const&;
    void Func(int) volatile&;
    void Func(int&&) volatile&;
    void Func(int) const volatile&;
    void Func(int&&) const volatile&;
    void Func(int) &&;
    void Func(int&&) &&;
    // (These are rather uncommon, just provided for completude.)
    void Func(int) const&&;
    void Func(int&&) const&&;
    void Func(int) volatile&&;
    void Func(int&&) volatile&&;
    void Func(int) const volatile&&;
    void Func(int&&) const volatile&&;
};

此问题有两种解决方案。一种是手动创建每个可能的过载,可能使用宏:

#define FWD(member, Func) \
    template<typename ...Args> \
    decltype(auto) Func(Args&&... args) & \
        noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \
        { return member.Func(std::forward<Args>(args)...); } \
    \
    template<typename ...Args> \
    decltype(auto) Func(Args&&... args) const& \
        noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \
        { return member.Func(std::forward<Args>(args)...); } \
    \
    template<typename ...Args> \
    decltype(auto) Func(Args&&... args) volatile& \
        noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \
        { return member.Func(std::forward<Args>(args)...); } \
    \
    template<typename ...Args> \
    decltype(auto) Func(Args&&... args) const volatile& \
        noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \
        { return member.Func(std::forward<Args>(args)...); } \
    \
    template<typename ...Args> \
    decltype(auto) Func(Args&&... args) && \
        noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \
        { return std::move(member).Func(std::forward<Args>(args)...); } \
    \
    template<typename ...Args> \
    decltype(auto) Func(Args&&... args) const&& \
        noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \
        { return std::move(member).Func(std::forward<Args>(args)...); } \
    \
    template<typename ...Args> \
    decltype(auto) Func(Args&&... args) volatile&& \
        noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \
        { return std::move(member).Func(std::forward<Args>(args)...); } \
    \
    template<typename ...Args> \
    decltype(auto) Func(Args&&... args) const volatile&& \
        noexcept(noexcept(member.Func(std::forward<Args>(args)...))) \
        { return std::move(member).Func(std::forward<Args>(args)...); }

template<typename Type>
struct Fwd {
    Type member;
    FWD(member, Func)
};

另一个解决方案是完全避免使用成员函数并使用自由函数:

template<typename Fwd, typename ...Args>
decltype(auto) Func(Fwd&& fwd, Args&&... args)
    noexcept(noexcept(std::forward<Fwd>(fwd).Func(std::forward<Args>(args)...))) {
    return std::forward<Fwd>(fwd).Func(std::forward<Args>(args)...);
}