Tôi thấy đây là giải pháp tao nhã nhất (và nó được chuyển tiếp tối ưu):
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
template<size_t N>
struct Apply {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T && t, A &&... a)
-> decltype(Apply<N-1>::apply(
::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
))
{
return Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
);
}
};
template<>
struct Apply<0> {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T &&, A &&... a)
-> decltype(::std::forward<F>(f)(::std::forward<A>(a)...))
{
return ::std::forward<F>(f)(::std::forward<A>(a)...);
}
};
template<typename F, typename T>
inline auto apply(F && f, T && t)
-> decltype(Apply< ::std::tuple_size<
typename ::std::decay<T>::type
>::value>::apply(::std::forward<F>(f), ::std::forward<T>(t)))
{
return Apply< ::std::tuple_size<
typename ::std::decay<T>::type
>::value>::apply(::std::forward<F>(f), ::std::forward<T>(t));
}
Ví dụ sử dụng:
void foo(int i, bool b);
std::tuple<int, bool> t = make_tuple(20, false);
void m()
{
apply(&foo, t);
}
Thật không may, GCC (ít nhất là 4.6) không biên dịch được điều này với "xin lỗi, chưa thực hiện: quá tải xáo trộn" (điều này có nghĩa đơn giản là trình biên dịch chưa thực hiện đầy đủ thông số kỹ thuật C ++ 11) và vì nó sử dụng các mẫu matrixdic, nên nó sẽ không làm việc trong MSVC, vì vậy nó ít nhiều vô dụng. Tuy nhiên, một khi có một trình biên dịch hỗ trợ thông số kỹ thuật, nó sẽ là cách tiếp cận tốt nhất IMHO. (Lưu ý: không khó để sửa đổi điều này để bạn có thể khắc phục các thiếu sót trong GCC hoặc để triển khai nó với Boost Pre xử lý, nhưng nó phá hỏng sự thanh lịch, vì vậy đây là phiên bản tôi đang đăng.)
GCC 4.7 hiện hỗ trợ mã này tốt.
Chỉnh sửa: Đã thêm chuyển tiếp xung quanh chức năng gọi thực tế để hỗ trợ biểu mẫu tham chiếu rvalue * trong trường hợp bạn đang sử dụng clang (hoặc nếu có ai thực sự có xung quanh để thêm nó).
Chỉnh sửa: Đã thêm thiếu chuyển tiếp xung quanh đối tượng chức năng trong cơ thể của hàm không áp dụng thành viên. Cảm ơn pheedbaq đã chỉ ra rằng nó đã bị mất.
Chỉnh sửa: Và đây là phiên bản C ++ 14 vì nó đẹp hơn rất nhiều (chưa thực sự biên dịch):
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
template<size_t N>
struct Apply {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T && t, A &&... a) {
return Apply<N-1>::apply(::std::forward<F>(f), ::std::forward<T>(t),
::std::get<N-1>(::std::forward<T>(t)), ::std::forward<A>(a)...
);
}
};
template<>
struct Apply<0> {
template<typename F, typename T, typename... A>
static inline auto apply(F && f, T &&, A &&... a) {
return ::std::forward<F>(f)(::std::forward<A>(a)...);
}
};
template<typename F, typename T>
inline auto apply(F && f, T && t) {
return Apply< ::std::tuple_size< ::std::decay_t<T>
>::value>::apply(::std::forward<F>(f), ::std::forward<T>(t));
}
Đây là phiên bản cho các chức năng thành viên (không được thử nghiệm nhiều!):
using std::forward; // You can change this if you like unreadable code or care hugely about namespace pollution.
template<size_t N>
struct ApplyMember
{
template<typename C, typename F, typename T, typename... A>
static inline auto apply(C&& c, F&& f, T&& t, A&&... a) ->
decltype(ApplyMember<N-1>::apply(forward<C>(c), forward<F>(f), forward<T>(t), std::get<N-1>(forward<T>(t)), forward<A>(a)...))
{
return ApplyMember<N-1>::apply(forward<C>(c), forward<F>(f), forward<T>(t), std::get<N-1>(forward<T>(t)), forward<A>(a)...);
}
};
template<>
struct ApplyMember<0>
{
template<typename C, typename F, typename T, typename... A>
static inline auto apply(C&& c, F&& f, T&&, A&&... a) ->
decltype((forward<C>(c)->*forward<F>(f))(forward<A>(a)...))
{
return (forward<C>(c)->*forward<F>(f))(forward<A>(a)...);
}
};
// C is the class, F is the member function, T is the tuple.
template<typename C, typename F, typename T>
inline auto apply(C&& c, F&& f, T&& t) ->
decltype(ApplyMember<std::tuple_size<typename std::decay<T>::type>::value>::apply(forward<C>(c), forward<F>(f), forward<T>(t)))
{
return ApplyMember<std::tuple_size<typename std::decay<T>::type>::value>::apply(forward<C>(c), forward<F>(f), forward<T>(t));
}
// Example:
class MyClass
{
public:
void foo(int i, bool b);
};
MyClass mc;
std::tuple<int, bool> t = make_tuple(20, false);
void m()
{
apply(&mc, &MyClass::foo, t);
}