Birincil sorun, işlev nesnesini oluşturuyor gibi görünüyor. Fonksiyonun tekrarlanan spesifikasyonundan kaçınmak ve üye fonksiyonlarını kapatmak için en kolay yaklaşım, ilgili türleri belirleyen bir fabrika fonksiyonunu kullanmaktır. Bu işlevin uygun şekilde aşırı yüklenmesi, normal ve üye fonksiyonlar arasında kolayca ayırt edilebilir. İşlev türünün yinelenen kullanımının, temsil ve imza türünün gerçekten farklı olduğu işlev nesneleri için olduğunu varsayalım.
template <typename R, typename... A>
funcWrap<R(A...), R(*)(A...)>
wrap(R(*fun)(A...)) { // deal with functions
return funcWrap<R(A...), R(*)(A...)>(fun);
}
template <typename Signature, typename F>
funcWrap<Signature, F>
wrap(F&& f) { // deal with function objects
return funcWrap<Signature, F>(std::forward<F>(f));
}
template <typename R, typename S, typename... A>
funcWrap<R(S&, A...), R (S::*)(A...)>
wrap(R(S::*mem)(A...)) {
return funcWrap<R(S&, A...), R (S::*)(A...)>(mem);
}
Sen üzerinde üyesi çağırmak için uygun bir nesne sizinIe başa gerekir bu
float add(float, float);
struct adder { float operator()(float, float); };
struct foo { foo mem(foo); };
int main() {
auto wfun = wrap(&add);
auto wobj = wrap<float(float, float)>(adder());
auto wmem = wrap(&foo::mem);
}
gibi wrap()
işlevini kullanmak istiyorum ve bazı uzmanlık ihtiyaç muhtemelen yönlendirilirsiniz işlev sarıcı funcWrap
. Ayrıca, üye fonksiyon durumu için const
üye fonksiyonları için uygun aşırı yüklenmelere sahip olmanız gerekebilir. Üye fonksiyonları için, üyeyi sararken nesneyi belirtmek ve uygun şekilde yakalamak da mantıklı olabilir. std::bind()
veya lambda işlev üyesi işlevlerini kullanmak, işlev nesneleri için sarmalayıcıyı kullanarak da bağlanabilir, ancak bu büyük olasılıkla, sonuç olarak ortaya çıkarılan imzanın belirtilmesini gerektirir. Aşağıda
bu sarma çalışması için gerekli tüm bit ve bobs gösteren C++ 11 ile derleme tam demo:
#include <iostream>
#include <sstream>
#include <stack>
#include <string>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
#include <cstddef>
// ----------------------------------------------------------------------------
template <typename T>
typename std::decay<T>::type makeArg(std::stack<std::string>& args) {
typename std::decay<T>::type rc;
if (args.empty() || !(std::istringstream(args.top()) >> rc)) {
throw std::runtime_error("can't create argument from '" + (args.empty()? "<empty>": args.top()) + "'");
}
args.pop();
return rc;
}
// ----------------------------------------------------------------------------
namespace util
{
template<typename T, T...>
struct integer_sequence {
};
template<std::size_t... I>
using index_sequence = integer_sequence<std::size_t, I...>;
template <typename T, std::size_t N, T... I>
struct integer_sequencer {
using type = typename integer_sequencer<T, N - 1, N - 1, I...>::type;
};
template <typename T, T... I>
struct integer_sequencer<T, 0, I...> {
using type = integer_sequence<T, I...>;
};
template<typename T, T N>
using make_integer_sequence = typename integer_sequencer<T, N>::type;
template<std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template <typename F, typename T, std::size_t... I>
auto apply_aux(F&& fun, T&& tuple, index_sequence<I...>) -> decltype(fun(std::get<I>(tuple)...)) {
return fun(std::get<I>(tuple)...);
}
template <typename F, typename T>
auto apply(F&& f, T&& t)
-> decltype(apply_aux(std::forward<F>(f), std::forward<T>(t), make_index_sequence<std::tuple_size<typename std::decay<T>::type>::value>())) {
return apply_aux(std::forward<F>(f), std::forward<T>(t), make_index_sequence<std::tuple_size<typename std::decay<T>::type>::value>());
}
}
// ----------------------------------------------------------------------------
template <typename S, typename F> class funcWrap;
template <typename R, typename... A, typename F>
class funcWrap<R(A...), F> {
private:
F fun;
public:
funcWrap(F fun): fun(fun) {}
std::string operator()(std::stack<std::string>& args) {
std::tuple<typename std::decay<A>::type...> t{ makeArg<A>(args)... };
std::ostringstream out;
out << util::apply(this->fun, t);
return out.str();
}
};
template <typename R, typename... A, typename S, typename... B>
class funcWrap<R(A...), R (S::*)(B...)> {
private:
R (S::*mem)(B...);
public:
funcWrap(R (S::*mem)(B...)): mem(mem) {}
std::string operator()(std::stack<std::string>& args) {
std::tuple<typename std::decay<A>::type...> t{ makeArg<A>(args)... };
std::ostringstream out;
out << util::apply([=](S& s, B... b){ return (s.*(this->mem))(b...); }, t);
return out.str();
}
};
// ----------------------------------------------------------------------------
template <typename R, typename... A>
funcWrap<R(A...), R(*)(A...)>
wrap(R(*fun)(A...)) { // deal with functions
return funcWrap<R(A...), R(*)(A...)>(fun);
}
template <typename Signature, typename F>
funcWrap<Signature, F>
wrap(F&& f) { // deal with function objects
return funcWrap<Signature, F>(std::forward<F>(f));
}
template <typename R, typename S, typename... A>
funcWrap<R(S&, A...), R (S::*)(A...)>
wrap(R(S::*mem)(A...)) {
return funcWrap<R(S&, A...), R (S::*)(A...)>(mem);
}
float add(float f0, float f1) { return f0 + f1; }
struct adder {
float value;
explicit adder(float value): value(value) {}
float operator()(float f0, float f1) {
return value + f0 + f1;
}
};
struct foo {
float value;
foo(): value() {}
explicit foo(float value): value(value) {}
foo mem(foo f) { return foo(value + f.value); }
};
std::istream& operator>> (std::istream& in, foo& f) {
return in >> f.value;
}
std::ostream& operator<< (std::ostream& out, foo const& f) {
return out << f.value;
}
int main() {
std::stack<std::string> args;
auto wfun = wrap(&add);
args.push("17.5");
args.push("42.25");
std::cout << "wfun result=" << wfun(args) << "\n";
auto wobj = wrap<float(float, float)>(adder(3.125));
args.push("17.5");
args.push("42.25");
std::cout << "wobj result=" << wobj(args) << "\n";
auto wmem = wrap(&foo::mem);
args.push("17.5");
args.push("42.25");
std::cout << "wmem result=" << wmem(args) << "\n";
}
Henüz bu -c + ile, (gcc 4.8 derlemeye alınamıyor + 1y), bir çift yazım hatalarını düzeltmesine rağmen (örneğin, toplayıcı için operatör() (yüzdürme, yüzdürme). Yaklaşımınız bana mantıklı geliyor. Şablonlarla her zamanki gibi beynime komik şeyler yapan detaylar. – user3849418
@ user3849418: Evet, birkaç yazım vardı: Kodu bir cep telefonunda bir araya getirdim. Bu yaklaşımın işe yaradığını gösteren eksiksiz bir uygulama ekledim. –
Oh vay. Ben ... hayranım. Bu, derler ve tam olarak istediğim ve ihtiyaç duyduğum şeyi yapar. Tam olarak şimdi anladım gibi davranmayacağım, ama üzerinde çalışacağım ve bu süreçte çok şey öğreneceğinden şüpheleniyorum. Teşekkür ederim. – user3849418