İşte size yararlı olabilecek herhangi bir boyut kuyruğuna bir genelleme. Ayrıca, çağrılabilir tipte daha geneldir (örn. Üye fonksiyon gösterici burada da test edilir).
#include <iostream>
#include <tuple>
#include <utility>
#include <string>
template <typename Callable> struct Invoke;
template <typename R, typename... Args>
struct Invoke<R(*)(Args...)> {
template <typename F, typename Tuple, std::size_t... Is, typename... As>
static R execute (F funcPtr, Tuple&& tuple, std::index_sequence<Is...>, As&&... as) {
return (*funcPtr)(std::forward<As>(as)..., std::get<Is>(std::forward<Tuple>(tuple))...);
}
};
template <typename R, typename C, typename... Args>
struct Invoke<R(C::*)(Args...)> {
template <typename F, typename Tuple, std::size_t... Is, typename... As>
static R execute (F f, Tuple&& tuple, std::index_sequence<Is...>, C& c, As&&... as) {
return (c.*f)(std::forward<As>(as)..., std::get<Is>(std::forward<Tuple>(tuple))...);
}
template <typename F, typename Tuple, std::size_t... Is, typename... As>
static R execute (F f, Tuple&& tuple, std::index_sequence<Is...>, C* c, As&&... as) {
return (c->*f)(std::forward<As>(as)..., std::get<Is>(std::forward<Tuple>(tuple))...);
}
};
template <typename R, typename C, typename... Args>
struct Invoke<R(C::*)(Args...) const> {
template <typename F, typename Tuple, std::size_t... Is, typename... As>
static R execute (F f, Tuple&& tuple, std::index_sequence<Is...>, C& c, As&&... as) {
return (c.*f)(std::forward<As>(as)..., std::get<Is>(std::forward<Tuple>(tuple))...);
}
template <typename F, typename Tuple, std::size_t... Is, typename... As>
static R execute (F f, Tuple&& tuple, std::index_sequence<Is...>, const C* c, As&&... as) {
return (c->*f)(std::forward<As>(as)..., std::get<Is>(std::forward<Tuple>(tuple))...);
}
};
template <typename Functor>
struct Invoke : Invoke<decltype(&Functor::operator())> {};
// etc...
template <typename R = void, typename F, typename Tuple, typename... Args>
R invokeWithTupleTail (F funcPtr, Tuple&& tuple, Args&&... args) {
return Invoke<F>::execute(funcPtr, std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{}, std::forward<Args>(args)...);
}
// Testing
struct Thing {
int call (char k, int n, double a, std::string b, int c) {
std::cout << k << ' ' << n << ' ' << a << ' ' << b << ' ' << c << '\n';
return 5;
}
int doIt (char k, int n, double a, std::string b, int c) const {
std::cout << k << ' ' << n << ' ' << a << ' ' << b << ' ' << c << '\n';
return 12;
}
int operator() (char k, int n, double a, std::string b, int c) const {
std::cout << k << ' ' << n << ' ' << a << ' ' << b << ' ' << c << '\n';
return 20;
}
};
void foo (char k, int n, double a, std::string b, int c) {
std::cout << k << ' ' << n << ' ' << a << ' ' << b << ' ' << c << '\n';
}
int bar (char k, int n, double a, std::string b, int c) {
std::cout << k << ' ' << n << ' ' << a << ' ' << b << ' ' << c << '\n';
return 10;
}
int main() {
const auto tupleTail = std::make_tuple(1.5, std::string("hello"), 42);
invokeWithTupleTail(foo, tupleTail, 'a', 8); // a 8 1.5 hello world 42
int a = invokeWithTupleTail<int>(&bar, tupleTail, 'a', 8); // a 8 1.5 hello world 42
std::cout << a << '\n'; // 10
Thing thing;
a = invokeWithTupleTail<int>(&Thing::call, tupleTail, thing, 'a', 8); // a 8 1.5 hello world 42
std::cout << a << '\n'; // 5
a = invokeWithTupleTail<int>(&Thing::doIt, tupleTail, &thing, 'a', 8); // a 8 1.5 hello world 42
std::cout << a << '\n'; // 12
a = invokeWithTupleTail<int>(&Thing::operator(), tupleTail, thing, 'a', 8); // a 8 1.5 hello world 42
std::cout << a << '\n'; // 20
}
int yerine double koymayı denediniz mi? –
En azından, CallWithExtraParameter (Callee, 1.0, string {"hello world"}); 'olmalıdır. Yapmamalı mı? –
skypjack
@skypjack Muhtemelen. (Benim gerçek kodum burada bir dizgeyi geçirmiyor, sadece MCVE için bazı rasgele türler seçtim) – immibis