Типы функций С++

У меня проблема с пониманием типов функций (они появляются, например, как параметр шаблона Signature для std::function):

typedef int Signature(int); // the signature in question

typedef std::function<int(int)>  std_fun_1;
typedef std::function<Signature> std_fun_2;

static_assert(std::is_same<std_fun_1, std_fun_2>::value,
              "They are the same, cool.");

int square(int x) { return x*x; }

Signature* pf = square;   // pf is a function pointer, easy
Signature f;              // but what the hell is this?
f(42);                    // this compiles but doesn't link

Переменная f не может быть назначена, но может быть вызвана. Weird. Для чего это полезно?

Теперь, если я const-qualify typedef, я все еще могу использовать его для создания дополнительных типов, но, по-видимому, ни для чего другого:

typedef int ConstSig(int) const;

typedef std::function<int(int) const>  std_fun_3;
typedef std::function<ConstSig>        std_fun_4;

static_assert(std::is_same<std_fun_3, std_fun_4>::value,
              "Also the same, ok.");

ConstSig* pfc = square; // "Pointer to function type cannot have const qualifier"
ConstSig fc;            // "Non-member function cannot have const qualifier"

Какой удаленный угол языка я попал сюда? Как называется этот странный тип и что я могу использовать его вне параметров шаблона?

Ответ 1

Вот соответствующий параграф из Стандарта. Это в значительной степени говорит само за себя.

8.3.5/10

Типичный тип функции может использоваться для объявления функции, но не должен использоваться для определения функции (8.4).

Пример:

typedef void F();
F  fv;         // OK: equivalent to void fv();
F  fv { }      // ill-formed
void fv() { }  // OK: definition of fv

Тип typedef типа функции, декларатор которого включает cv-qualifier-seq, должен использоваться только для объявления типа функции для нестатической функции-члена, для объявления типа функции, к которому относится указатель на элемент, или объявить тип функции верхнего уровня другой декларации typedef функции.

Пример:

typedef int FIC(int) const;
FIC f;               // ill-formed: does not declare a member function
struct S {
  FIC f;             // OK
};
FIC S::*pm = &S::f;  // OK

Ответ 2

В вашем случае std_fun_1 и std_fun_2 являются идентичными объектами с идентичными сигнатурами типа. Они оба std::function<int(int)> и могут содержать указатели на объекты или вызываемые объекты типа int(int).

pf является указателем на int(int). То есть, он выполняет ту же основную задачу, что и std::function, но без механизма этого класса или поддержки экземпляров вызываемых объектов.

Аналогично, std_fun_3 и std_fun_4 являются идентичными объектами с идентичными сигнатурами типа и могут содержать указатели на объекты или вызываемые объекты типа int(int) const.

Аналогично, pfc является указателем на функцию типа int(int) const и может содержать указатели на функции этого типа, но не экземпляры вызываемых объектов.

Но f и fc являются объявлениями функций.

Строка:

Signature fc;

Тождественно эквивалентно:

int fc(int) const;

Это объявление для функции с именем fc типа int(int) const.

Здесь ничего странного не происходит. Вы просто столкнулись с синтаксисом, который вы, вероятно, уже понимаете, с той точки зрения, к которой вы не привыкли.