ฉันพบว่านี่เป็นโซลูชันที่หรูหราที่สุด (และได้รับการส่งต่ออย่างเหมาะสมที่สุด):
#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));
}
ตัวอย่างการใช้งาน:
void foo(int i, bool b);
std::tuple<int, bool> t = make_tuple(20, false);
void m()
{
apply(&foo, t);
}
น่าเสียดายที่ GCC (อย่างน้อย 4.6) ล้มเหลวในการรวบรวมสิ่งนี้ด้วย "ขออภัยไม่ได้ใช้งาน: mangling overload" (ซึ่งหมายความว่าคอมไพเลอร์ยังไม่ได้ใช้ข้อกำหนด C ++ 11 อย่างสมบูรณ์) และเนื่องจากมันใช้เทมเพลตที่หลากหลายจึงไม่เคยชิน ทำงานใน MSVC ดังนั้นจึงไม่มีประโยชน์มากหรือน้อย อย่างไรก็ตามเมื่อมีคอมไพเลอร์ที่รองรับข้อมูลจำเพาะแล้วมันจะเป็นแนวทางที่ดีที่สุดของ IMHO (หมายเหตุ: มันไม่ยากที่จะแก้ไขสิ่งนี้เพื่อให้คุณสามารถแก้ไขข้อบกพร่องใน GCC หรือนำไปใช้กับ Boost Preprocessor แต่มันทำลายความสง่างามดังนั้นนี่คือเวอร์ชันที่ฉันกำลังโพสต์)
GCC 4.7 รองรับรหัสนี้ได้แล้ว
แก้ไข: เพิ่มไปข้างหน้าสำหรับการเรียกใช้ฟังก์ชันจริงเพื่อรองรับแบบฟอร์มอ้างอิง rvalue * ในกรณีที่คุณใช้ clang (หรือถ้ามีใครเข้ามาเพิ่ม)
แก้ไข: เพิ่มไปข้างหน้าที่ขาดหายไปรอบ ๆ วัตถุฟังก์ชันในเนื้อความของฟังก์ชันใช้งานที่ไม่ใช่สมาชิก ขอบคุณ pheedbaq ที่ชี้ให้เห็นว่ามันหายไป
แก้ไข: และนี่คือเวอร์ชัน C ++ 14 เนื่องจากเป็นรุ่นที่ดีกว่ามาก (ยังไม่ได้รวบรวม):
#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));
}
นี่คือเวอร์ชันสำหรับฟังก์ชั่นสมาชิก (ยังไม่ผ่านการทดสอบมากนัก!):
using std::forward;
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)...);
}
};
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));
}
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);
}