これは、大量のコードを投稿せずに説明するのは少し複雑になるでしょうが、最善を尽くします。通常の無料の関数とインスタンスのメソッドの両方をコンソールにバインドして、単純なキーワードを使用して呼び出すことができるようにする必要があるゲーム内コンソールを作成しています。コンソールをバインドできるすべてのメソッド/関数は sf::String パラメータを必要とし、sf::String を返します。(私はゲームに SFML を使用しており、sf は SFML の名前空間です)
[注: 4 つのクラス (Console、CFunctionInterface、CFunction、および CMethod) はすべて、同じファイル (console.h) で宣言されています。それらのメンバーはすべて、単一のファイル (console.cpp) 内で定義されています]
これを設定するために、1 つの親 (CFunctionInterface) と 2 つの子 (CFunction、CMethod) の「コンテナー」クラスがあります。親には、その内部に 1 つの public メソッドがあります。
sf::String call(sf::String p_Value);
CFunction の宣言は次のようになります。
class CFunction : public CFunctionInterface
{
public:
typedef sf::String (*FFP)(sf::String); //free function pointer type
CFunction(const FFP p_Function);
sf::String call(const sf::String p_Value);
private:
FFP m_Function;
};
CMethod の宣言は次のようになります。
template <typename ClassType>
class CMethod : public CFunctionInterface
{
public:
typedef sf::String (ClassType::*MFP)(sf::String); //member function pointer type
CMethod(const ClassType* p_Instance, const MFP p_Function);
sf::String call(const sf::String p_Value);
private:
ClassType* m_Instance;
MFP m_Function;
};
すべてが一目瞭然で、各クラスに対して call() が何をするか想像できると思います。
コンソールに戻ると、
std::multimap <string, CFunctionInterface* >
すべての関数ポインタを格納するように設定します。関数を呼び出したい場合、このマップが繰り返され、入力関数名がキーの 1 つと一致する場合、そのキーの値が呼び出されます。例 (name は目的の関数の目的のキー、param は関数に渡したい sf::String です [push_back() はコンソールにメッセージを出力するコンソールのメソッドです]):
for(auto iter = functions.begin(); iter!= functions.end(); iter++)
{
if(iter->first == name)
{
push_back(iter->second->call(param));
return;
}
}
push_back("Error! Function with name: " + name + " not found!");
これで、コンソール内に関数をバインドおよびバインド解除するためのメソッドがいくつかあります。ここで問題が発生します。
template <typename ClassType>
void bindFunction(const string name, const ClassType* instance, sf::String (ClassType::*func)(sf::String));
void bindFunction(const string name, sf::String (*func)(sf::String));
void unbindFunction(const string name);
最後の 2 つの関数は美しく機能します。問題ありません。しかし、それはそのテンプレート野郎です。彼の定義は次のとおりです (console.cpp 内):
template <typename ClassType>
void CConsole::bindFunction(const string name, const ClassType* instance, sf::String (ClassType::*func)(sf::String))
{
//Checks to see if name is already in use
for(auto iter = functions.begin(); iter != functions.end(); iter++)
{
if(iter->first == name)
{
push_back("Error! Attempting to bind function. The name \'" + name + "\' is already in use!");
return;
}
}
//Everything checks out
CMethod* temp = new CMethod<ClassType> (instance, func);
functions.insert( pair<string, CFunctionInterface* > (name, temp) );
}
プログラム全体で彼をまったく呼び出さないと、コンパイルして問題なく実行されます。しかし、私がそれを呼び出そうとすると; 次のエラーが表示されます。
1>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall CConsole::bindFunction<class CDog>(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class CDog const *,class sf::String (__thiscall CDog::*)(class sf::String))" (??$bindFunction@VCDog@@@CConsole@@QAEXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PBVCDog@@P83@AE?AVString@sf@@V45@@Z@Z) referenced in function _main
1>S:\Users\Logan\documents\visual studio 2012\Projects\newConsole\Debug\newConsole.exe : fatal error LNK1120: 1 unresolved externals
「int main()」での呼び出しは次のようになります。
CDog* rex = new CDog;
console->bindFunction<CDog>("bark", rex, &CDog::bark);
CDog は、"Woof!" を返す public bark() メソッドを持つ単純なクラスです。console は main の内部で作成されており、新しい CConsole オブジェクトへの単なるポインターです。「console.h」はインクルードされ、#include ループはありません。私はチェックしました。
私はオンラインで少しググったことがありますが、このようなリンカーエラーは見つかりませんでした. インクルードを忘れるか、インクルード ループを持つことが常に問題でした。
私が間違っていることと、それを修正する方法を誰かが知っていますか? これを読んでいただきありがとうございます。- ローガン