Понимание аргумента шаблона для std::function в С++ 11?

Я освежаю некоторые С++ 11, и мне немного трудно что-то понять.

std::function позволяет мне передавать любой тип Callable как объект функции. Я знаю, что он делает и как его использовать.

void foo(int a, int b) {} 
std::function<void (int, int)> bar = foo;
...

bar — это вызываемый объект, целью которого является foo, функция, которая принимает два целых числа в качестве параметров.

Чего я не понимаю, так это того, что означает void (int, int)...

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

Но void (int, int), похоже, не "называет тип".

  • void (*)(int, int) — это указатель на функцию, возвращающую void, которая принимает два целых числа.
  • void (Foo*::)(int, int) — это указатель на функцию Foo, возвращающую void, которая принимает два целых числа.

На самом деле следующий игрушечный фрагмент компилируется нормально.

class Foo {};
int main(int, char**)
{
    void (*)(int, int);
    void (Foo*::)(int, int);
}

Но добавление выражения void (int, int) вызывает ошибку времени компиляции.

Я еще немного покопался, прежде чем опубликовать свой вопрос. Компилируется следующий фрагмент кода:

class Foo {};

template <typename T>
struct Bar
{
    typedef T type;
};

void a(int b, int c) {}

int main(int, char**)
{
    void (*)(int, int);
    void (Foo::*)(int, int);

    Bar<int (int, int)> bar;
}

Но попытка использовать Bar::type каким-либо образом приводит к другой ошибке: "недопустимо объявленный тип функции".


TLDR: что именно означает выражение void (int, int) и почему это допустимый параметр шаблона?

Спасибо за любую помощь, которую вы можете отправить мне.


person JDR    schedule 10.06.2015    source источник
comment
Какой компилятор и параметры вы используете для своего игрушечного фрагмента? Насколько я могу судить, он не должен компилироваться.   -  person dyp    schedule 11.06.2015
comment
Я использую g++ 4.6.3 на Ubuntu 12.04LTS. Компиляция с простым g++ test.cpp -o test, без флагов и прочего.   -  person JDR    schedule 11.06.2015
comment
Связанные/дубликаты: Синтаксис шаблонов C++ с параметрами типа функции   -  person dyp    schedule 11.06.2015
comment
никаких флагов и прочего Для многих компиляторов это не очень хорошая идея. Для g++ я бы предложил использовать -std=c++11 -pedantic -Wall -Wextra, чтобы указать версию стандарта, которой он должен следовать, и предупредить о нестандартных расширениях, которые он принимает.   -  person dyp    schedule 11.06.2015
comment
Большое спасибо за второй ответ, это был именно тот ответ, который я искал. Я искал его и действительно не столкнулся с ним. Это сигнатура функции. Сигнатуры функций можно передавать как параметры шаблона -- я не знал... Еще раз спасибо.   -  person JDR    schedule 11.06.2015
comment
Итак, вы согласны с тем, что void (*)(int, int) называет тип и что это указатель на что-то. Как бы вы назвали тип объекта, на который он указывает?   -  person David Schwartz    schedule 11.06.2015
comment
@JDR Кто-то очень педантичный может указать, что void(int,int) на самом деле не является сигнатурой функции, поскольку сигнатура (не шаблонных) функций не содержит тип возвращаемого значения;) (Это делает меня очень педантичным, я думаю.) Его можно назвать типом функции, поскольку это тип функции. Вы даже можете объявить, но не определять функцию, используя тип функции. Например. using FT = void(int); FT myFunc; void myFunc(int) {}   -  person dyp    schedule 11.06.2015


Ответы (2)


Не все типы имеют значения. void — наиболее известный пример.

void(int,int) — это просто тип без значений. И это полезно, значит, это используется.

Тип можно использовать вне аргументов шаблона в нескольких местах. Например, его можно использовать для объявления метода или функции, или указатель на тип можно использовать как указатель на функцию, или ссылку как ссылку на функцию.

person Yakk - Adam Nevraumont    schedule 11.06.2015

dyp указал мне на правильный ответ. Это был дублирующий вопрос.

void (int, int) представляет собой «сигнатуру функции», а сигнатуры функций могут передаваться как параметры шаблона.

person JDR    schedule 10.06.2015
comment
В частности, void(int,int) — это не только подпись, но и в определенных контекстах также тип. А именно тип объекта, на который указывает void(*)(int,int). Однако в C++ функции не являются настоящими объектами по той же причине, по которой void(int,int) не является реальным типом: тип не имеет размера. - person Mooing Duck; 11.06.2015
comment
@TBohne void тоже не имеет размера, как и int[]. Однако стандарт C++ называет все их типы. void(int,int) также не является подписью, если использовать терминологию стандарта. - person dyp; 11.06.2015