18

如果您有模板类或模板函数(或两者的组合),您如何绑定该函数(保留模板类型参数)?

在下面的一篇文章中,我得到了一些关于基本语法的帮助,以绑定到具有显式模板类型参数的函数,但在此过程中失去了提供模板类型参数的能力。

是否有可能让它工作,以便仍然可以为将来的调用提供模板类型参数?

清理了这段代码很多,但它显然不会编译,因为我找不到正确的语法,(有没有办法做到这一点)?

删除了“矢量”要求以简化这一点:

谢谢您的帮助!

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


   }
};
4

4 回答 4

15

关键问题是在 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);
于 2013-02-16T20:17:34.003 回答
10

模板参数std::function应该是模板类型替换完成后函数的签名。在您的情况下,既TemplateType不会FunctionTemplateType影响成员函数的签名,也不会影响MyFunction- 它总是会返回 astd::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对象并接受一个 type 的参数std::string。您可以像这样调用这些函数之一:

Storage::Functions[0]("something");
于 2013-02-06T12:28:44.397 回答
5

如果我理解你的话...... :)

你想做的事情是不可能的,因为对于 template<class T> void foo(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++ 无法即时生成代码。我认为您可能知道该函数可能使用的所有可能类型的参数,因此这可能不是问题。

于 2013-02-16T18:21:34.490 回答
4

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

工作空间链接

于 2013-02-06T11:18:31.097 回答