Это, вероятно, философский вопрос, но я столкнулся с следующей проблемой:
Если вы определяете функцию std:: и не инициализируете ее правильно, ваше приложение будет разбиваться, например:
typedef std::function<void(void)> MyFunctionType;
MyFunctionType myFunction;
myFunction();
Если функция передается как аргумент, например:
void DoSomething (MyFunctionType myFunction)
{
myFunction();
}
Затем, конечно, он также падает. Это означает, что я вынужден добавить контрольный код следующим образом:
void DoSomething (MyFunctionType myFunction)
{
if (!myFunction) return;
myFunction();
}
Требование этих проверок дает мне флэш-обратную связь со старыми днями C, где вам также необходимо было явно проверить все аргументы указателя:
void DoSomething (Car *car, Person *person)
{
if (!car) return; // In real applications, this would be an assert of course
if (!person) return; // In real applications, this would be an assert of course
...
}
К счастью, мы можем использовать ссылки на С++, что мешает мне писать эти проверки (предполагая, что вызывающий объект не передал содержимое nullptr функции:
void DoSomething (Car &car, Person &person)
{
// I can assume that car and person are valid
}
Итак, почему экземпляры std:: function имеют конструктор по умолчанию? Без конструктора по умолчанию вам не нужно будет добавлять проверки, как и для других нормальных аргументов функции. И в тех редких случаях, когда вы хотите передать "необязательную" std:: функцию, вы все равно можете передать указатель на нее (или использовать boost:: optional).