考虑一个具有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
)并为用户提供相同的界面?
答案 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)...);
}