Идеальная пересылка функции-члена члена данных?

Рассмотрим класс, который имеет 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)...);
}
};

Какой правильный синтаксис (использование C ++ 14 auto / variadic templates / forward …) для передачи заданной функции _data в MyClass (например insert здесь) и предоставить такой же интерфейс для пользователя?

3

Решение

Правильный синтаксис такой:

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)...);
}
};
5

Другие решения

к действительно переадресовать вызов функции-члену, необходимо учитывать необходимость правильной переадресации *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)...);
}
2

По вопросам рекламы [email protected]