Подтвердить что ты не робот

С++ Как привязать шаблонные функции с помощью функции std:: bind/std::

Если у вас есть шаблонный шаблон или шаблонная функция (или комбинация из двух), как вы связываете эту функцию (сохраняя параметр типа шаблона)?

Мне была оказана некоторая помощь в отношении базового синтаксиса в приведенном ниже сообщении, чтобы привязываться к функциям с явными параметрами типа шаблона, но терять способность предоставлять параметры типа шаблона в процессе.

Можно ли заставить это работать, чтобы все еще можно было предоставлять параметры типа шаблона в будущих вызовах?

Убрал этот код много, но он, очевидно, не будет компилироваться, потому что я не могу найти правильный синтаксис (есть ли способы сделать это)?

Убрано требование "вектора", чтобы упростить это:

Спасибо за помощь!

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


   }
};
4b9b3361

Ответ 1

Ключевыми проблемами являются то, что в С++ 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 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);

Ответ 2

Аргумент шаблона для 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. Вы можете вызвать одну из следующих функций:

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

Ответ 3

Если я понял тебя правильно...:)

То, что вы хотите сделать, невозможно, потому что для шаблона < 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)

К сожалению, в любом случае вам необходимо создать экземпляр шаблонов функций, прежде чем вставлять их в контейнер, потому что С++ не может генерировать код на лету. Я думаю, что возможно, что вы знаете все возможные типы аргументов, которые могут использоваться с этой функцией, чтобы это не было проблемой.

Ответ 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;
}

ссылка liveworkspace