Fungsi mengambil pointer-ke-metode terlepas dari ketidakjelasannya
Saya ingin menerapkan fungsi umum yang akan merujuk ke objek dan penunjuk ke fungsi anggotanya dan menjalankannya. Namun saya tidak dapat melakukannya ketika kelas saya memiliki metode const dan non-const karena saya perlu memberikan dua kelebihan beban:
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...))
{
return (object.*method)(Us{}...);
}
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...) const)
{
return (object.*method)(Us{}...);
}
Apakah ada cara untuk menulis hanya 1 fungsi template yang akan menerima pointer metode const dan non-const sehingga saya tidak perlu menulis kode dua kali? Saya menggunakan C ++ 14.
Untuk gambaran yang lebih luas, apa yang pada akhirnya ingin saya capai adalah melewatkan parameter ke-3, buffer data dari mana argumen metode akan diekstraksi - oleh karena itu fungsi templat untuk menanganinya seumum mungkin.
Jawaban
Berikut alternatif C ++ 14 tanpa menggunakan std::function
.
apa yang ingin saya capai pada akhirnya adalah melewatkan parameter ke-3, buffer data dari mana argumen metode akan diekstraksi - karenanya fungsi templat untuk menanganinya seumum mungkin
Apa yang Anda gunakan di situs panggilan akan diteruskan dengan sempurna di sini:
template<typename Class, typename Func, typename... Args>
decltype(auto) callMethod_impl(Class& object, Func method, Args&&... args) {
return (object.*method)(std::forward<Args>(args)...);
}
template<typename Ret, typename Class, typename... Us, typename... Args>
Ret callMethod(Class& object, Ret(Class::*method)(Us...), Args&&... args) {
return callMethod_impl(object, method, std::forward<Args>(args)...);
}
template<typename Ret, typename Class, typename... Us, typename... Args>
Ret callMethod(const Class& object, Ret(Class::*method)(Us...) const, Args&&... args) {
return callMethod_impl(object, method, std::forward<Args>(args)...);
}
Demo
Jika Anda perlu Ret
di callMethod_impl
, hanya menambahkannya sebagai parameter template dan menyebutnya seperti callMethod_impl<Ret>(...)
dari callMethod
overloads ( Demo ).
Jawaban singkatnya adalah, jangan terapkan sendiri, ini sudah dilakukan untuk Anda dalam bentuk std::invoke:
#include <functional>
struct A {
void foo(int x);
void bar(int x) const;
};
void example() {
A a;
std::invoke(&A::foo, a, 3);
std::invoke(&A::bar, a, 3);
}
Melihat bahwa Anda telah menambahkan tag C ++ 14 dalam retrospeksi, dokumentasi std::invokememiliki contoh implementasi yang dapat Anda gunakan dalam proyek Anda.
Tanpa std::invoke
, Anda hanya dapat melakukan beberapa solusi umum yang lebih banyak atau lebih sedikit, berdasarkan jenis penghapusan. Menggunakan std::function
memungkinkan Anda membuat fungsi proxy untuk memperlakukan fungsi Anda pada pijakan yang sama:
#include <iostream>
#include <functional>
template<typename Ret, typename ...Us>
Ret callMethod_impl(std::function<Ret(Us...)> f) {
// common implementation here
return f(Us{}...);
}
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(Class &object, Ret (Class::*method)(Us...)) {
return callMethod_impl(std::function<Ret(Us...)>(std::bind(method, object)));
}
template<typename Ret, typename Class, typename ...Us>
Ret callMethod(const Class &object, Ret (Class::*method)(Us...) const) {
return callMethod_impl(std::function<Ret(Us...)>(std::bind(method, object)));
}
struct Foo {
int bar() const { return 1; }
float bar() { return 2.1f; };
};
int main() {
Foo f;
std::cout << callMethod(f, &Foo::bar) << std::endl;
}
Perhatikan bahwa volatile
fungsi (+ kombinasi) tidak diperlakukan di sini, tetapi mungkin Anda tidak memerlukan keumuman penuh melainkan solusi pragmatis.