简体   繁体   English

C ++如何使用std :: bind / std :: function引用模板化函数

[英]C++ How to Reference Templated Functions using std::bind / std::function

If you have a templated class or a templated function, (or combination of the two), how do you bind that function, (preserving the template type parameter)? 如果你有一个模板化的类或模板化的函数(或两者的组合),你如何绑定该函数,(保留模板类型参数)?

I was given some help about the basic syntax in a post below, to bind to functions with explicit template type parameters, but lose the ability to provide template type parameters in the process. 我在下面的帖子中给出了一些关于基本语法的帮助,用显式模板类型参数绑定到函数,但是在这个过程中失去了提供模板类型参数的能力。

Is it possible to get this to work so that it is still possible to provide template type parameters with future calls? 是否有可能使其工作,以便仍然可以提供未来调用的模板类型参数?

Cleaned up this code a lot, but it obviously won't compile because I can't find the correct syntax, (are there any ways of doing this)? 清理过这段代码很多,但显然无法编译,因为我找不到正确的语法,(有没有办法做到这一点)?

Removed the "vector" requirement to simplify this: 删除了“向量”要求以简化此操作:

Thanks for the help! 谢谢您的帮助!

#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);


   }
};

The key issues is that in C++11 you cannot do something like: 关键问题是在C ++ 11中你不能做类似的事情:

// Doesn't compile
template <typename TemplateType>
static std::function<void(std::shared_ptr<TemplateType>)> Function;

Classes and Functions can be templated, but not member properties. 类和函数可以是模板化的,但不是成员属性。

The "Magic" is: “魔术”是:

/*******************************************************************/
// 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;

You can then Bind a templated function to this function like: 然后,您可以将模板化函数绑定到此函数,如:

// 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);
   }
}

And you can invoke all of this and provide a templated type parameter like so: 您可以调用所有这些并提供模板化类型参数,如下所示:

//Invocation
std::shared_ptr<std::string> parameter;
parameter->get() = "Hello World".
Storage::FunctionContainer<std::string>::Function(parameter);

The template argument for std::function should be the signature of the function after template type substitution has been done. 在完成模板类型替换之后std::function的模板参数应该是std::function的签名。 In your case, neither TemplateType nor FunctionTemplateType have an effect on the signature of the member function MyFunction - it will always return a std::string and take a single std::string argument. 在您的情况下, TemplateTypeFunctionTemplateType都不会影响成员函数MyFunction的签名 - 它将始终返回std::string并获取单个std::string参数。 Therefore, the std::function you're going to store in your std::vector should be: 因此,您要存储在std::vectorstd::function应该是:

static std::vector<std::function<std::string(std::string)>> Functions;

Recall that a member function has an implicit first argument this . 回想一下,一个成员函数具有一个隐含的第一个参数this You need to bind the first argument of MyClass<...>::MyFunc<...> to the object you want it to be called on. 您需要将MyClass<...>::MyFunc<...>的第一个参数绑定到要调用它的对象。 Presumably, since you're binding the function in MyClass 's constructor, you want the object to be that MyClass instance. 据推测,既然您在MyClass的构造函数中绑定了该函数,那么您希望该对象成为MyClass实例。 That means your push_back should look like this: 这意味着你的push_back应如下所示:

Storage::Functions.push_back(
  std::bind(&MyClass<TemplateType>::MyFunction<int>, this,
    std::placeholders::_1)
);

Now the function that is pushed into Functions is bound to your MyClass object and takes a single argument of type std::string . 现在,推入Functions绑定到MyClass对象,并采用类型为std::string的单个参数。 You can call one of these functions like so: 您可以像这样调用以下函数之一:

Storage::Functions[0]("something");

If I understood you right... :) 如果我理解你的话...... :)

What you want to do is not possible because for template<class T> void foo(T) functions foo<int>() and foo<double> are of different types and you can not create vector holding pointers to both that functions directly because vector is homogeneous container. 您想要做的是不可能的,因为对于模板<class T> void foo(T)函数foo <int>()和foo <double>属于不同的类型,并且您不能创建向量保持指向这两个函数的向量,因为矢量是同质的容器。

To overcome that we can use boost::variant<> to either store pointers to different types of functions or to store arguments of functions. 为了克服这个问题,我们可以使用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)

Unfortunately, in any case you will need to instantiate function templates before inserting them to container because C++ can not do code generation on the fly. 不幸的是,在任何情况下,您都需要在将函数模板插入容器之前对其进行实例化,因为C ++无法动态执行代码生成。 I think that it is possible that you know all possible types of arguments that the function may be used with so that may be not a problem. 我认为您可能知道函数可能使用的所有可能类型的参数,因此可能不是问题。

MyClass's c-tor doesn't know anything about FunctionTemplateType that's why it can push_back only explicit specialized (sorry, it's term of mine... I don't know the right term) like this MyClass的c-tor对FunctionTemplateType一无所知,这就是为什么它只能push_back 显式专门 (对不起,这是我的术语......我不知道正确的术语),就像这样

#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;
}

liveworkspace link liveworkspace链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM