テンプレート化されたクラスまたはテンプレート化された関数(または2つの組み合わせ)がある場合、その関数をどのようにバインドしますか(テンプレート型パラメーターを保持します)?
以下の投稿で、明示的なテンプレート型パラメーターを使用して関数にバインドするための基本的な構文についていくつかのヘルプが提供されましたが、プロセスでテンプレート型パラメーターを提供する機能が失われました。
これを機能させて、将来の呼び出しでテンプレートタイプのパラメーターを提供できるようにすることは可能ですか?
このコードをたくさんクリーンアップしましたが、正しい構文が見つからないため、明らかにコンパイルされません(これを行う方法はありますか?)
これを単純化するために「ベクトル」要件を削除しました。
助けてくれてありがとう!
#include <functional>
#include <vector>
#include <string>
/***************************************/
template <typename CommandTemplateType>
class Storage
{
public:
// No idea how to define this vector to allow Template Parameters
// static std::vector<std::function<void<ParameterTemplateType>
// (std::shared_ptr<ParameterTemplateType>)>> Functions;
// I really don't need the collection, a single member would kick start my research:
static std::function<void<ParameterTemplateType>(std::shared_ptr<ParameterTemplateType>)> Function;
template <typename ParameterTemplateType>
static void Execute(ParameterTemplateType parameter)
{
// Look up index, or loop through all..
// I am trying to invoke the bound function with a template param:
// Functions[index]<ParameterTemplateType>(parameter);
// preferably, just:
Function<ParameterTempalteType>(parameter);
}
};
/***************************************/
template <typename TemplateType>
class MyClass
{
template <typename ParameterTemplateType>
void MyFunction(ParameterTemplateType myParameter)
{
// Do something;
}
MyClass()
{
std::string parameter = L"Test String";
// Do not know how to include the
// template<typename ParameterTemplateType> definition to bind call.
// Storage::Functions.Push_back(
// std::bind(&MyClass::MyFunction<ParameterTemplateType>,
// this, std::placeholders::_1));
// Or just something like:
Storage::Function = std::bind(&MyClass::MyFunction<ParameterTemplateType>,
this, std::placeholders::_1));
/***************************************/
// Call the bound function with an explicit parameter somehow:
std::string parameter = L"Test String";
Storage::Execute<std::string>(parameter);
}
};
重要な問題は、C++ 11では次のようなことはできないということです。
// Doesn't compile
template <typename TemplateType>
static std::function<void(std::shared_ptr<TemplateType>)> Function;
クラスと関数はテンプレート化できますが、メンバープロパティはテンプレート化できません。
「魔法」は次のとおりです。
/*******************************************************************/
// Define a Function Pointer in a Container
class Storage
{
template <typename TemplateType>
struct FunctionContainer {
static std::function<void(std::shared_ptr<TemplateType>)> Function;
};
};
/*******************************************************************/
// Initialize FunctionContainer's Static Function Pointer if using static pointer.
template <typename TemplateType>
std::function<void(std::shared_ptr<TemplateType>)> Storage
::FunctionContainer<TemplateType>::Function;
次に、テンプレート化された関数を次のようにこの関数にバインドできます。
// Bind Function Pointer in Container to a Local Function
class MyClass
{
template <typename TemplateType>
void MyFunction(std::shared_ptr<TemplateType> parameter)
{
// Do something.
// You can make this templated or non-templated.
}
MyClass()
{
// If you really want, you can templatize std::string in the following:
Storage::FunctionContainer<std::string>::Function
= std::bind(&MyFunction<std::string>, this, std::placeholders::_1);
}
}
そして、これらすべてを呼び出して、次のようなテンプレート型パラメーターを提供できます。
//Invocation
std::shared_ptr<std::string> parameter;
parameter->get() = "Hello World".
Storage::FunctionContainer<std::string>::Function(parameter);
std::function
のテンプレート引数は、関数のシグネチャである必要があります後テンプレートタイプの置換が行われました。あなたの場合、TemplateType
もFunctionTemplateType
もメンバー関数MyFunction
の署名に影響を与えません-それは常にstd::string
を返し、単一のstd::string
引数を取ります。したがって、std::function
に保存するstd::vector
は次のようになります。
static std::vector<std::function<std::string(std::string)>> Functions;
メンバー関数には暗黙の最初の引数this
があることを思い出してください。 MyClass<...>::MyFunc<...>
の最初の引数を、呼び出されるオブジェクトにバインドする必要があります。おそらく、MyClass
のコンストラクターで関数をバインドしているので、オブジェクトをそのMyClass
インスタンスにする必要があります。つまり、Push_back
は次のようになります。
Storage::Functions.Push_back(
std::bind(&MyClass<TemplateType>::MyFunction<int>, this,
std::placeholders::_1)
);
これで、Functions
にプッシュされた関数はMyClass
オブジェクトにバインドされ、タイプstd::string
の単一の引数を取ります。次のように、これらの関数の1つを呼び出すことができます。
Storage::Functions[0]("something");
私があなたを正しく理解したなら... :)
Template <classT>の場合voidfoo(T)関数foo <int>()とfoo <double>は異なるタイプであり、両方の関数へのポインターを保持するベクトルを直接作成できないため、実行したいことは不可能です。ベクトルは均質なコンテナです。
これを克服するには、boost :: Variant <>を使用して、さまざまなタイプの関数へのポインターを格納するか、関数の引数を格納します。
template<class T> void foo(T);
typedef boost::variant<void (*)(int), void (*)(double)> func_ptr_variant;
std::vector<func_ptr_variant> v;
v.Push_back(foo<int>);
v.Push_back(foo<double>);
typedef boost::variant<int, double> argument;
std::vector<void (*)(argument)) v;
v.Push_back(foo);
v.Push_back(bar);
// foo and bar are defined as void foo(argument a) and void bar(argument a)
残念ながら、C++はその場でコード生成を行うことができないため、いずれの場合でも、関数テンプレートをコンテナーに挿入する前にインスタンス化する必要があります。関数が使用される可能性のあるすべてのタイプの引数を知っている可能性があるので、問題はないかもしれません。
MyClassのc-torはFunctionTemplateType
について何も知らないので、Push_backのみexplicit specialized(申し訳ありませんが、私の用語です。 ..正しい用語がわからない)このように
#include <functional>
#include <vector>
#include <string>
struct Storage
{
// Have no idea what this signature should really be:
static std::vector<std::function<void ()>> Functions;
};
std::vector<std::function<void ()>> Storage::Functions;
template <typename TemplateType>
class MyClass
{
template <typename FunctionTemplateType>
std::string MyFunction(std::string myParameter)
{
return "Hellö: " + myParameter;
}
public:
MyClass()
{
Storage::Functions.Push_back(
std::bind( & MyClass<TemplateType>::MyFunction<std::string>, this, "borisbn" )
// ^^^^^^^^^^^
);
}
};
int main() {
MyClass<int> obj;
}