Может ли tr1::function проглотить возвращаемые значения?
Пункт 3 часто задаваемых вопросов boost:: function специально посвящен интересующему меня сценарию:
Почему есть обходные пути для пустых возвратов? C++ позволяет им! Пустые возвраты разрешены стандартом C++, как в следующем фрагменте кода:
void f(); void g() { return f(); }
Это допустимое использование boost:: function, потому что возврат void не используется. С пустыми возвратами мы попытались бы скомпилировать некорректный код, подобный следующему:
int f(); void g() { return f(); }
По сути, отсутствие использования возвращаемых значений void позволяет boost:: function проглотить возвращаемое значение. Это согласуется с тем, что пользователь может назначать и вызывать функции и функциональные объекты с параметрами, которые не совсем совпадают.
К сожалению, это не работает в VS2008:
int Foo();
std::tr1::function<void()> Bar = Foo;
Это приводит к ошибкам, начиная с:
c:\Program Files\Microsoft Visual Studio 9.0\VC\include\xxcallfun(7) : error C2562: 'std::tr1::_Callable_fun<_Ty>::_ApplyX' : 'void' function returning a value
Это сбой реализации VS2008 TR1? Это работает в VS2010? TR1 обращается к этой возможности? Как насчет C++0x?
1 ответ
Я считаю, что tr1 решает эту проблему. N1836 (последняя версия tr1) гласит:
Функциональный объект f типа F может вызываться для типов аргументов T1, T2, ..., TN и типа возврата R, если при заданных значениях t1, t2, ..., tNoftypesT1, T2, ..., TN соответственно INVOKE(f, t1, t2, ..., tN) корректно сформирован ([3.3]) и, если R не является пустым, конвертируется в R.
В вашем примере R является недействительным, и поэтому последняя часть требований для Callable
(конвертируется в R) игнорируется.
Однако похоже, что C++0x (C++11) меняет правила. В С ++ 11 Callable
определяется как INVOKE(f, t1, t2, ..., tN, R)
который определен в [func.require] как требующий INVOKE(f, t1, t2, ..., tN)
быть неявно конвертируемым в R, за исключением случаев, когда R является недействительным. Так что в C++ 11 ваш пример должен потерпеть неудачу.