나는 이것이 가장 우아한 해결책이라고 생각합니다 (그리고 최적으로 전달됩니다).
#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; // 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);
}