函數延遲綁定的C++實現

聲明:本博客做者與此博客https://blog.csdn.net/cjw_soledad/article/details/105585806相同ios

  • 本文代碼須要c++17支持(可自行修改以兼容c++11)

概述

有時候咱們會對相同的數據作不一樣的操做,例如:c++

int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }
int do_sth(int a, int b, const std::string& function_name) {
	if (function_name == "add") return add(a, b);
	if (function_name == "mul") return mul(a, b);
}

這種作法是可行的,可是當咱們還須要添加sub(a, b)div(a, b)等等的多個函數時,每添加一個函數,咱們都要在do_sth中添加一個if,很容易出錯,也不符合開閉原則。編程

另外一種實現方法是將每一個操做單獨封裝成一個類,而後使用工廠模式建立。這種作法是符合開閉原則的,可是每添加一個函數就要添加一個類未免也太繁瑣了。安全

理想狀況下,假若有一門語言同時結合了c++, Java,Python,應該這樣添加函數:函數

// 函數管理類FunctionManager
//     @Register():將函數註冊到這個類中
//     getFunction(): 將已註冊的函數返回
class FunctionManager;

@Register("add") // 將函數add註冊到FunctionManager,經過字符串"add"可以找到這個函數
int add(int a, int b) { return a + b; }
@Register("mul") // 將函數mul註冊到FunctionManager,經過字符串"mul"可以找到這個函數
int mul(int a, int b) { return a * b; }
int do_sth(int a, int b, const std::string& function_name) {
	// 函數管理類根據function_name返回一個std::function
	std::function<int(int, int)> Function = FunctionManager.getFunction(function_name);
	return Function(a, b);
}
  • FunctionManager: 管理函數的類
  • @Register("Add"): 將函數指針和函數簽名(可以惟一標識該函數的字符串)添加到FunctionManager
  • FunctionManager.getFunction(): 根據函數簽名返回函數指針

很明顯,當前的c++不支持@Register,退而求其次咱們使用宏進行註冊,最終本文實現的效果是(在最後提供了可運行的完整程序):ui

// xxx.h
int add(int a, int b);
// xxx.cpp
// 註冊函數,參數爲:變量名(ADD),函數簽名("ADD"),函數指針(add)
_REGISTER_FUNCTION(ADD, "ADD", add);
int add(int a, int b) { return a + b; }
// main.cpp
int do_sth(int a, int b, const std::string& func_sig) {
	// FunctionManager是一個單例
	auto p_function_manager = FunctionManager<decltype(add)>::getInstance();
	// 此處返回已註冊的函數
	auto func = p_function_manager->getFunction(func_sig);
	return 
}

實現

咱們將管理函數的類命名爲FunctionManager。仔細分析咱們的需求,不難發現實際上咱們須要根據字符串查找註冊的函數對象。this

查找的實現

STL中已經有了可以知足咱們需求的std::map<std::string, FunctionType>容器,所以查找功能已經實現了。須要注意的有:編碼

  • FunctionType須要外部提供,而函數的返回值、參數都會改變都會影響FunctionType,咱們不可能把FunctionType硬編碼到程序中,這時候就須要模板。
  • 因爲函數指針不可以做爲函數的返回值,獲取函數的接口只能返回std::function,所以map中存儲的也應當是std::function
  • 考慮到程序中僅有一個FunctionManager,將FunctionManager設置爲單例更方便(同時也能知足註冊函數的需求)。
template <typename FunctionType>
class FunctionManager {
	// 沒有delete這個指針,考慮到這是demo,忽略這個問題
	inline static FunctionManager<FunctionType>* p_function_manager = nullptr;

	std::map<std::string, FunctionType> m_sig_func_map;

public:
	static FunctionManager<FunctionType>* get_instance() {
		if (!p_function_manager) p_function_manager = new FunctionManager<FunctionType>;
		return p_function_manager;
	}
	
	// 實際上不能使用運算符[],由於當map中sig不存在時會自動建立一個<sig, empty>對象,demo中忽略這個問題
	FunctionType get_function(const std::string& sig) { return m_sig_func_map[sig]; }
};

註冊的實現

註冊實際上就是將函數簽名(字符串)和函數(std::function對象)添加到FunctionManager::m_sig_func_map中,只須要添加一個接口:spa

// 也可使用insert,兩者間存在一點區別
	void register_function(const std::string& sig, FunctionType function) { m_sig_func_map[sig] = function; }

嘗試使用

到這裏咱們已經可使用FunctionManager了:.net

int add(int a, int b) { return a + b; }
void use() {
	std::function<int(int, int)> a(add);
	FunctionManager<std::function<decltype(add)>>::get_instance()->register_function("add", a);
	auto another_add = FunctionManager<std::function<decltype(add)>>::get_instance()->get_function("add");
	std::cout << another_add(1, 3) << std::endl;
}

咱們看到FunctionManager的使用實際上是很不方便的:

  • 註冊時須要提供對應函數的std::function對象,實際上咱們在使用的時候只但願提供函數的指針
  • 註冊和獲取函數時都須要須要獲取單例

這些冗雜的代碼能夠交給單獨的接口進行封裝:

template <typename FunctionPtr>
void register_function(const std::string& function_sig, FunctionPtr function_ptr) {
	auto function_obj = static_cast<std::function<FunctionPtr>>(function_ptr);
	auto p_function_manager = FunctionManager<decltype(function_obj)>::get_instance();
	p_function_manager->register_function(function_sig, function_obj);
}

template <typename FunctionType>
FunctionType get_function(const std::string& function_sig) {
	auto p_function_manager = FunctionManager<FunctionType>::get_instance();
	return p_function_manager->get_function(function_sig);
}

int main(int argc, char* argv[]) {
	register_function<decltype(add)>("add", add); // 只提供指針
	auto another_add = get_function<std::function<int(int, int)>>("add");
	std::cout << another_add(1, 4) << std::endl;
	return 0;
}

相比之下使用起來方便多了,實際上到這裏FunctionManager的實現就已經完成了,可是還要讓FunctionManager更好用,以及讓FunctionManager適用於更多類型的函數,下面纔是文章的重點

註冊

現有的FunctionManager若是直接使用還會存在一個問題:須要由用戶保證在get_functionregister_function。在demo中這並非大問題,可是放在大型項目中,get_function在多個文件中被屢次調用,須要由用戶保證register_function在全部get_function前執行,這實在是太危險了。穩妥一點的方法是:

void register_all_function() {
	auto p_function_manager = /* get singleton instance */ ;
	p_function_manager->register_function(sig_1, func_1);
	p_function_manager->register_function(sig_2, func_2);
	// ...
}
int main {
	register_all_function();
}

main最開始的時候進行註冊是最安全的作法,可是每添加一個函數,用戶就要在register_all_function中進行註冊,這也違背了開閉原則。

所以咱們有了新的需求:main函數執行前完成對象的註冊。有兩種方法可以在main前執行一段函數:靜態成員變量全局變量須要注意的是兩者均須要在cpp文件中定義,不可以在頭文件中。經過register_function爲全局變量賦值可以在main前執行register_function,所以咱們還須要爲register_function添加一個返回值:

template <typename FunctionPtr>
bool register_function(const std::string& function_sig, FunctionPtr function_ptr) {
	// ...
	return true;
}

用全局變量註冊函數

經過定義全局變量可以在main執行前將須要的函數註冊至FunctionManager。爲了在使用更方便、代碼可讀性更高,FunctionManager提供了一個宏_REGISTER_FUNCTION,用於封裝註冊函數。其原理以下:

#define _REGISTER_FUNCTION(FunctionSig, FunctionPtr) \
	bool b = register_function<decltype(FunctionPtr)>(FunctionSig, FunctionPtr);

這樣帶來了新的問題:在實際使用時,一個.cpp文件內一般會有多個類型相同的函數的實現,_REGISTER_FUNCTION將被調用屢次:

_REGISTER_FUNCTION("ADD", add);
int add(int a, int b) { return a + b; }
_REGISTER_FUNCTION("MUL", mul); // 編譯錯誤,重複定義的變量b
int mul(int a, int b) { return a * b; }

屢次調用_REGISTER_FUNCTION會致使全局變量b被重複定義。所以須要用戶手動提供不重複的變量名(VariableName)以防止編譯錯誤,最終_REGISTER_FUNCTION的實現以下:

#define _REGISTER_FUNCTION(VariableName, FunctionSig, FunctionPtr) \
	bool Bool##VariableName = register_function<decltype(FunctionPtr)>(FunctionSig, FunctionPtr);

// xxx.h
int add(int, int);
// xxx.cpp
_REGISTER_FUNCTION(ADD, "ADD", add);
int add(int a, int b) { return a + b; }

FunctionManager適配的函數

普通函數

  • 普通函數
float add(float a, float b) { return a + b; }
_REGISTER_FUNCTION(ADD, "ADD", add);

auto new_add = get_function<decltype(add)>("ADD");
  • 命名空間內的函數
namespace FunctionManagerTest {
    float add(float a, float b) { return a + b; }
}
_REGISTER_FUNCTION(ADD, "ADD", FunctionManagerTest::add);

auto new_add = get_function<std::function<decltype(FunctionManagerTest::add)>>("ADD");
  • 模板函數
template<typename T> T addT(T a, T b) { return a + b; }
_REGISTER_FUNCTION(ADD, "ADD", addT<int>);

 auto new_add = get_function<std::function<decltype(addT<int>)>>("ADD");

類內函數

  • 靜態函數
class Real {
public:
    static float add(float a, float b) { return a + b; }
};
_REGISTER_FUNCTION(ADD, "ADD", Real::add);

auto new_add = get_function<std::function<decltype(Real::add)>>("ADD");
  • 模板類的靜態函數
template<typename T>
class Add {
public:
    static float add(T a, T b) { return a + b; }
};
_REGISTER_FUNCTION(ADD, "ADD", Add<int>::add);

auto new_add = get_function<std::function<decltype(Add<int>::add)>>("ADD");

適配成員函數

如今的FunctionManager可以支持的函數少了很重要的一類:成員函數。由於成員函數在被調用時會有一個this指針做爲隱式參數,顯然直接經過&Real::add是沒法得到this指針的。這意味着咱們須要添加新的接口。

template<typename FunctionPtr, typename ObjectPtr>
bool register_member_function(FunctionPtr func_ptr, ObjectPtr obj_ptr) {
	return true;
}

回看需求,咱們但願可以在FunctionManager中獲取到函數後,可以直接調用;同時FunctionManager中管理的也只是可以直接調用的std::function對象,並未區分紅員函數或者非成員函數。如今問題簡化爲如何爲某一個函數提供一個默認的參數(對象指針),提供後,咱們就能像調用普通函數同樣調用成員函數了。

咱們知道std::bind可以將函數與參數綁定,返回一個Callable對象該對象可以使用對應的std::funtion接收;結合std::placeholder還可以在調用返回的Callable時提供參數:

class Real { public: int add(int a, int b) { return a + b; } }

Real real;
std::function<int(int,int)> binded_add = std::bind(&Real::add, &real, std::placeholders::_1, std::placeholders::_2);
std::cout << binded_add(2, 1) << std::endl;

如今如何提供默認參數的問題解決了,可是另外一個問題又出現了:代碼中的std::function<int(int,int)>是硬編碼進去的,確定不能實裝,咱們須要一種可以自動填充std::function<>內模板參數的方法。在網上找了大半天后,終於有了一種基於模板的解決方案

template <typename Ret, typename Struct, typename ...Args, typename ObjectPtr>
bool register_memeber_function(const std::string& sig, Ret(Struct::* func_ptr)(Args...) const, ObjectPtr obj_ptr) {
	std::function<Ret(Args...)> func = std::bind(func_ptr, obj_ptr);
	auto p_funciton_manager = FunctionManager<decltype(func)>::get_instance();
	p_function_manager->register_function(sig, func);
	return true;
}

class Real { public: int add(int a, int b) { return a + b; } }

Real real;
bool b = register_member_function("ADD", &Real::add, &real);

&Real::add做爲參數傳入後可以自動推導出Ret, Struct以及可變參數Args;因爲咱們會綁定對象指針,所以咱們只須要返回值Ret,參數Args做爲std::function的模板參數。這樣一來std::function的模板參數問題終於解決了。

然而如今的代碼是沒法經過編譯的,由於std::bind中沒有添加正確數量的std::placeholder。這個問題的解決須要用到一點元編程,StackOverflow上有人用自定義placeholder以及std::make_integer_sequence的方法來實現參數可變的std::bind

// https://stackoverflow.com/questions/26129933/bind-to-function-with-an-unknown-number-of-arguments-in-c
template<int N>
struct my_placeholder { static my_placeholder ph; };

template<int N>
my_placeholder<N> my_placeholder<N>::ph;

namespace std {
    template<int N>
    struct is_placeholder<::my_placeholder<N>> : std::integral_constant<int, N> { };
}

template<class R, class T, class...Types, class U, int... indices>
std::function<R (Types...)> bind_first(std::function<R (T, Types...)> f, U val, std::integer_sequence<int, indices...> /*seq*/) {
    return std::bind(f, val, my_placeholder<indices+1>::ph...);
}
template<class R, class T, class...Types, class U>
std::function<R (Types...)> bind_first(std::function<R (T, Types...)> f, U val) {
    return bind_first(f, val, std::make_integer_sequence<int, sizeof...(Types)>());
}

這裏的核心思想是在模板中傳入長度與參數個數相同的整數序列,而且爲每一個序列中的整數添加一個placeholder。其實並不須要本身定義一個placeholder,由於std::placeholder的實現是相似的:

// PLACEHOLDER ARGUMENTS
namespace placeholders {
    _INLINE_VAR constexpr _Ph<1> _1{};
    _INLINE_VAR constexpr _Ph<2> _2{};
} // namespace placeholders

結合已有實現以及std::placeholder的解決方案以下:

template <typename Ret, typename Struct, typename ...Args, typename ObjectPtr, int... Indices>
std::function<Ret(Args...)> erase_class_info(Ret(Struct::* func_ptr)(Args...), ObjectPtr obj_ptr, std::integer_sequence<int, Indices...>)
{
	std::function<Ret(Args...)> erased_function = std::bind(func_ptr, obj_ptr, std::_Ph<Indices + 1>{}...);
	return erased_function;
}

template <typename Ret, typename Struct, typename ...Args, typename ObjectPtr>
bool register_memeber_function(const std::string& sig, Ret(Struct::* func_ptr)(Args...), ObjectPtr obj_ptr) {
	std::function<Ret(Args...)> erased_func = erase_class_info(func_ptr, obj_ptr, std::make_integer_sequence<int, sizeof...(Args)>());
	auto p_funciton_manager = FunctionManager<decltype(erased_func)>::get_instance();
	p_funciton_manager->register_function(sig, erased_func);
	return true;
}

另外,成員函數添加const之後的函數類型是不一樣的,簡單地添加兩個相似接口能夠解決這個問題:

template <typename Ret, typename Struct, typename ...Args, typename ObjectPtr, int... Indices>
std::function<Ret(Args...)> erase_class_info(Ret(Struct::* func_ptr)(Args...) const, ObjectPtr obj_ptr, std::integer_sequence<int, Indices...>)
{
	std::function<Ret(Args...)> erased_function = std::bind(func_ptr, obj_ptr, std::_Ph<Indices + 1>{}...);
	return erased_function;
}

template <typename Ret, typename Struct, typename ...Args, typename ObjectPtr>
bool register_memeber_function(const std::string& sig, Ret(Struct::* func_ptr)(Args...) const, ObjectPtr obj_ptr) {
	std::function<Ret(Args...)> erased_func = erase_class_info(func_ptr, obj_ptr, std::make_integer_sequence<int, sizeof...(Args)>());
	auto p_funciton_manager = FunctionManager<decltype(erased_func)>::get_instance();
	p_funciton_manager->register_function(sig, erased_func);
	return true;
}

如今已經支持成員函數的註冊了:

class Real {
public:
	int add(int a, int b) const { return a + b; }
	int sub(int a, int b) { return a - b; }
};

Real real;
bool b1 = register_memeber_function("real", &Real::add, &real);
bool b2 = register_memeber_function("REAL", &Real::sub, &real);
auto f1 = get_function<std::function<int(int, int)>>("real");
auto f2 = get_function<std::function<int(int, int)>>("REAL");
std::cout << f1(2, 1) << std::endl;
std::cout << f2(2, 1) << std::endl;

至此FunctionManager實現完成


補充

更簡單的接口

前面提到了使用靜態成員變量也可以實現註冊功能,用靜態成員變量註冊函數
能夠進一步減小用戶須要寫的代碼,FunctionManager但願不須要用戶提供變量名。參考boost宏BOOST_CLASS_EXPORT,其利用模板類和靜態成員變量實現了類的註冊,而且不須要用戶提供變量名,其原理以下:

namespace boost::archive::detail::extra_detail {
    template<> struct init_guid<ClassToRegister> {
        static guid_initializer<ClassToRegister> const& g; //靜態成員g
    }
    static guid_initializer<ClassToRegister> const& g = register_function(); // 定義g,同時註冊類
}

BOOST_CLASS_EXPORT仍是不能知足需求,由於BOOST_CLASS_EXPORT用於註冊類,假若用於註冊多個相同類型的函數會致使靜態成員g重複定義,而實際註冊函數時同一類型的函數每每會被註冊屢次。如:

int add(int a, int b) { return a + b; }
int mul(int a, int b) { return a * b; }
_BOOST_LIKE_REGISTER("ADD", add);
_BOOST_LIKE_REGISTER("MUL", mul); // 靜態成員g重複定義

FunctionManager經過命名空間解決重複定義這一問題,宏_EASY_REGISTER_FUNCTION實現以下:

#define _EASY_REGISTER_FUNCTION(FunctionSig, FunctionPtr) \
    namespace VicentChenSpace { \
        namespace Dummy { \
            namespace FunctionPtr { \
                struct Dummy { \
                    static bool const& b; \
                }; \
            } \
        } \
    } \
    bool const& VicentChenSpace::Dummy::FunctionPtr::Dummy::b = register_function<decltype(::FunctionPtr)>(FunctionSig, ::FunctionPtr); \

雖然_EASY_REGISTER_FUNCTION使用起來更方便,但有如下問題:

  • 須要c++17支持
  • 不支持註冊帶有模板的函數
  • 命名空間相關問題

可運行demo

#include <functional>
#include <map>
#include <iostream>

#define _REGISTER_FUNCTION(VariableName, FunctionSig, FunctionPtr) \
	bool Bool##VariableName = register_function<decltype(FunctionPtr)>(FunctionSig, FunctionPtr);

template <typename FunctionType>
class FunctionManager {
	// 沒有delete這個指針,考慮到這是demo,忽略這個問題
	inline static FunctionManager<FunctionType>* p_function_manager = nullptr;

	std::map<std::string, FunctionType> m_sig_func_map;

public:
	static FunctionManager<FunctionType>* get_instance() {
		if (!p_function_manager) p_function_manager = new FunctionManager<FunctionType>;
		return p_function_manager;
	}

	// 也可使用insert,兩者間存在一點區別
	void register_function(const std::string& sig, FunctionType function) { m_sig_func_map[sig] = function; }
	
	// 實際上不能使用運算符[],由於當map中sig不存在時會自動建立一個<sig, empty>對象,demo中忽略這個問題
	FunctionType get_function(const std::string& sig) { return m_sig_func_map[sig]; }
};

template <typename FunctionPtr>
bool register_function(const std::string& function_sig, FunctionPtr function_ptr) {
	auto function_obj = static_cast<std::function<FunctionPtr>>(function_ptr);
	auto p_function_manager = FunctionManager<decltype(function_obj)>::get_instance();
	p_function_manager->register_function(function_sig, function_obj);
	return true;
}

template <typename FunctionType>
FunctionType get_function(const std::string& function_sig) {
	auto p_function_manager = FunctionManager<FunctionType>::get_instance();
	return p_function_manager->get_function(function_sig);
}

template <typename Ret, typename Struct, typename ...Args, typename ObjectPtr, int... Indices>
std::function<Ret(Args...)> erase_class_info(Ret(Struct::* func_ptr)(Args...), ObjectPtr obj_ptr, std::integer_sequence<int, Indices...>)
{
	std::function<Ret(Args...)> erased_function = std::bind(func_ptr, obj_ptr, std::_Ph<Indices + 1>{}...);
	return erased_function;
}

template <typename Ret, typename Struct, typename ...Args, typename ObjectPtr>
bool register_memeber_function(const std::string& sig, Ret(Struct::* func_ptr)(Args...), ObjectPtr obj_ptr) {
	std::function<Ret(Args...)> erased_func = erase_class_info(func_ptr, obj_ptr, std::make_integer_sequence<int, sizeof...(Args)>());
	auto p_funciton_manager = FunctionManager<decltype(erased_func)>::get_instance();
	p_funciton_manager->register_function(sig, erased_func);
	return true;
}

template <typename Ret, typename Struct, typename ...Args, typename ObjectPtr, int... Indices>
std::function<Ret(Args...)> erase_class_info(Ret(Struct::* func_ptr)(Args...) const, ObjectPtr obj_ptr, std::integer_sequence<int, Indices...>)
{
	std::function<Ret(Args...)> erased_function = std::bind(func_ptr, obj_ptr, std::_Ph<Indices + 1>{}...);
	return erased_function;
}

template <typename Ret, typename Struct, typename ...Args, typename ObjectPtr>
bool register_memeber_function(const std::string& sig, Ret(Struct::* func_ptr)(Args...) const, ObjectPtr obj_ptr) {
	std::function<Ret(Args...)> erased_func = erase_class_info(func_ptr, obj_ptr, std::make_integer_sequence<int, sizeof...(Args)>());
	auto p_funciton_manager = FunctionManager<decltype(erased_func)>::get_instance();
	p_funciton_manager->register_function(sig, erased_func);
	return true;
}

// ----- 普通函數註冊 ----- //
// 普通函數
int add(int a, int b) { return a + b; }
_REGISTER_FUNCTION(ADD, "ADD", add);
int mul(int a, int b) { return a * b; }
_REGISTER_FUNCTION(MUL, "MUL", mul);

// 命名空間內函數
namespace VicentSpace { int add(int a, int b) { return a + b; } }
_REGISTER_FUNCTION(NAMESPACE_ADD, "NAMESPACE_ADD", VicentSpace::add);

// 模板函數
template<typename T> T addT(T a, T b) { return a + b; }
_REGISTER_FUNCTION(TEMPLATE_ADD, "TEMPLATE_ADD", addT<int>);

// ----- 類內函數註冊 ----- //
class Real {
public:
	int add(int a, int b) const { return a + b; }
	int sub(int a, int b) { return a - b; }
	static int mul(int a, int b) { return a * b; }
};
Real real;

template <typename T>
class RealT {
public:
	T addT(T a, T b) const { return a + b; }
	T subT(T a, T b) { return a - b; }
	static T mulT(T a, T b) { return a * b; }
};
RealT<int> real_t;

// 靜態函數
_REGISTER_FUNCTION(STATIC_MUL, "STATIC_MUL", Real::mul);

// 靜態模板函數
_REGISTER_FUNCTION(STATIC_TEMPLATE_MUL, "STATIC_TEMPLATE_MUL", RealT<int>::mulT);

// 成員函數
bool b1 = register_memeber_function("REAL_ADD", &Real::add, &real);
bool b2 = register_memeber_function("REAL_SUB", &Real::sub, &real);

// 模板成員
bool b3 = register_memeber_function("REALT_ADD", &RealT<int>::addT, &real_t);
bool b4 = register_memeber_function("REALT_SUB", &RealT<int>::subT, &real_t);

int main(int argc, char* argv[]) {

	// 普通函數
	auto normal_add = get_function<std::function<decltype(add)>>("ADD");
	auto normal_mul = get_function<std::function<decltype(add)>>("MUL");
	std::cout << "Normal Add 1 + 2 = " << normal_add(1, 2) << std::endl;
	std::cout << "Normal Mul 1 * 2 = " << normal_mul(1, 2) << std::endl;

	// 命名空間內函數
	auto namespace_add = get_function<std::function<decltype(VicentSpace::add)>>("NAMESPACE_ADD");
	std::cout << "Namespace Add 1 + 2 = " << namespace_add(1, 2) << std::endl;

	// 模板函數
	auto template_add = get_function<std::function<int(int, int)>>("TEMPLATE_ADD");
	std::cout << "Template Add 1 + 2 = " << template_add(1, 2) << std::endl;

	// 靜態函數
	auto static_mul = get_function<std::function<int(int, int)>>("STATIC_MUL");
	std::cout << "Static Mul 1 * 2 = " << static_mul(1, 2) << std::endl;
	
	// 靜態模板函數
	auto static_template_mul = get_function<std::function<int(int, int)>>("STATIC_TEMPLATE_MUL");
	std::cout << "Static Template Mul 1 * 2 = " << static_template_mul(1, 2) << std::endl;
	
	// 成員函數
	auto real_add = get_function<std::function<int(int, int)>>("REAL_ADD");
	auto real_sub = get_function<std::function<int(int, int)>>("REAL_SUB");
	std::cout << "Member Add 2 + 1 = " << real_add(2, 1) << std::endl;
	std::cout << "Const Member Sub 2 - 1 = " << real_sub(2, 1) << std::endl;

	// 模板成員
	auto real_t_add = get_function<std::function<int(int, int)>>("REALT_ADD");
	auto real_t_sub = get_function<std::function<int(int, int)>>("REAL_SUB");
	std::cout << "Template Member Add 2 + 1 = " << real_t_add(2, 1) << std::endl;
	std::cout << "Template Const Member Sub 2 - 1 = " << real_t_sub(2, 1) << std::endl;
	
	return 0;
}

參考

  1. StackOverflow - Call a function before main
  2. StackOverflow - std::bind to std::function?
  3. StackOverflow - generic member function pointer as a template parameter
  4. StackOverflow - Bind to function with an unknown number of arguments in C++
  5. cppreference - std::bind
相關文章
相關標籤/搜索