Типы функций С++
У меня проблема с пониманием типов функций (они появляются, например, как параметр шаблона 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
.
Здесь ничего странного не происходит. Вы просто столкнулись с синтаксисом, который вы, вероятно, уже понимаете, с той точки зрения, к которой вы не привыкли.