イネマルのプログラミング備忘録

趣味プログラマーのメモ

C++で各種関数を同一のコンテナに格納する

関数をコンテナに格納する

テーブルに関数(std::function)を登録して関数名の文字列で呼び出す
みたいなことをやったときにクラスのメソッドの登録で
微妙にハマり、備忘録行き

注意

引数の数が同一でないと格納できない方法です。
引数が違うメソッドの格納は、ここでは扱いません。

目的

以下のタイプの関数を同一のコンテナに格納してみる
 ・メンバ関数(クラスのメソッド
 ・ラムダ式
 ・グローバル関数

確認用のプログラム

※動作確認は、VC2013

#include <iostream>
#include <array>
#include <string>
#include <functional>
#include <unordered_map>

// 登録関数の型定義
typedef std::function<void()>	RegistFuncType;

// メンバ関数用定義
struct MemberFunction
{
	MemberFunction()
		:	// メンバ関数はstd::bindでstd::functionに代入する
			m_memberFunc(std::bind(&MemberFunction::Method_01, this)),
			// 引数があれば(std::placeholders::_n)で追加する
			m_memberArgFunc(std::bind(&MemberFunction::Method_02, this, std::placeholders::_1, std::placeholders::_2))
	{}

	~MemberFunction()
	{}

	void Method_01(){
		std::cout << "メンバ関数" << std::endl;
	}

	void Method_02(int value1, int value2){
		std::cout << value1 + value2 << std::endl;
	}

	RegistFuncType m_memberFunc;
	std::function<void(int,int)> m_memberArgFunc;
};

// ラムダ式
const auto LambdaFunc = [](){
	std::cout << "ラムダ式" << std::endl;
};

// グローバル関数
void GlobalFunc(){
	std::cout << "グローバル関数" << std::endl;
}

int main()
{
	using namespace std;

	// 関数テーブル
	unordered_map<string, RegistFuncType>	funcTable;

	// キー配列
	array<string, 3> keyArray{{
		"メンバ関数",
		"ラムダ式",
		"グローバル関数"
	}};

	// 登録確認関数
	auto FailTableRegist = [&funcTable](const string key) ->bool{
		if (funcTable[key] == nullptr){
			std::cerr << key << " : "<< "登録失敗" << std::endl;
			return true;
		}
		return false;
	};

	// クラスメンバの登録
	MemberFunction cf;
	funcTable[keyArray[0]] = cf.m_memberFunc;
	if (FailTableRegist(keyArray[0])){
		return -1;
	}
	// 引数ありのメンバの呼び出し
	//cf.m_memberArgFunc(1, 2);

	// ラムダ式の登録
	funcTable[keyArray[1]] = LambdaFunc;
	if (FailTableRegist(keyArray[1])){
		return -1;
	}

	// グローバル関数の登録
	funcTable[keyArray[2]] = GlobalFunc;
	if (FailTableRegist(keyArray[2])){
		return -1;
	}

	// 呼び出し
	for (const auto& key : keyArray){
		funcTable[key]();
	}

	rewind(stdin), getchar();
	return 0;
}

あとがき

関数をコンテナに格納して使用する状況自体が
だいぶ特殊だと思ったりするけど、
プラグインから関数を呼び出すときに使用したので
使うときは使う。(正攻法とは言っていない)