Синтаксис шаблона C++ std::function-like

В С++ 11 вы можете создать экземпляр std::function следующим образом:

std::function<void(int)> f1;
std::function<int(std::string, std::string)> f2;
//and so on

Но хотя информации о шаблонах с переменным числом аргументов в Интернете предостаточно, мне не удалось найти ни одной статьи о том, как написать шаблон, подобный std::function, который принимал бы аргументы в скобках. Может ли кто-нибудь объяснить синтаксис и его ограничения или хотя бы указать на существующее объяснение?


person Smiles    schedule 22.12.2014    source источник


Ответы (2)


В этом нет ничего особенного, это обычный тип функции. Когда вы объявляете такую ​​функцию:

int foo(char a, double b)

Тогда его тип int (char, double). Один из способов «развернуть» отдельные типы аргументов и тип возвращаемого значения — использовать частичную специализацию шаблона. В основном std::function выглядит примерно так:

template <class T>
struct function; // not defined

template <class R, class... A>
struct function<R (A...)>
{
  // definition here
};
person Angew is no longer proud of SO    schedule 22.12.2014
comment
Итак, если я правильно понимаю, int(char, double) интерпретируется как один тип функции, но мы можем затем извлечь тип возвращаемого значения и список параметров с частичной специализацией? - person Smiles; 22.12.2014
comment
@Cynic Да, именно так это и работает. Я отредактировал ответ соответственно. - person Angew is no longer proud of SO; 22.12.2014
comment
Мне нужен синтаксис типа template <typename F> void foo(F(int) intCallable){...} :/ - person jaskmar; 03.01.2017
comment
@MariuszJaskółka Синтаксис для этого foo(F intCallable(int)). Это точно так же, как любой другой синтаксис функции: имя находится между типом возвращаемого значения и списком аргументов. - person Angew is no longer proud of SO; 03.01.2017

Почти как любой другой шаблон, поскольку int(std::string, std::string) — это просто тип.

Вот действительно наивный пример, который компилируется:

template <typename FType>
struct Functor
{
   Functor(FType* fptr) : fptr(fptr) {}

   template <typename ...Args>
   void call(Args... args)
   {
      fptr(args...);
   }

private:
   FType* fptr;
};

void foo(int x, char y, bool z) {}

int main()
{
   Functor<void(int, char, bool)> f(&foo);
   f.call(1, 'a', true);
   //f.call(); // error: too few arguments to function
}

На самом деле у вас будет специализация FType как ReturnType(ArgTypes...), хотя мой наивный пример уже даст вам необходимую проверку, если вы попытаетесь вызвать его совместимыми способами.

person Lightness Races in Orbit    schedule 22.12.2014