Наверное, это философский вопрос, но я столкнулся со следующей проблемой:
Если вы определите std::function и не инициализируете ее правильно, ваше приложение рухнет, например так:
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
...
}
К счастью, мы можем использовать ссылки на C++, что не позволяет мне писать эти проверки (при условии, что вызывающая сторона не передала в функцию содержимое nullptr:
void DoSomething (Car &car, Person &person)
{
// I can assume that car and person are valid
}
Итак, почему экземпляры std::function имеют конструктор по умолчанию? Без конструктора по умолчанию вам не пришлось бы добавлять проверки, как и для других обычных аргументов функции. И в тех «редких» случаях, когда вы хотите передать «необязательную» функцию std::, вы все равно можете передать на нее указатель (или использовать boost:: optional).
functors
: sgi.com/tech/stl/functors.html - person Marcin Gil   schedule 23.09.2011strlen
, чем вызывая вашу функцию. - person Steve Jessop   schedule 23.09.2011no-op
, а не функцию, выбрасывающую исключение, это довольно просто — до тех пор, пока вы возвращаетеvoid
. Обработка всех типов (включая ссылки) на удивление сложна: stackoverflow.com/q/31274869/1858225 - person Kyle Strand   schedule 07.07.2015