Разница между версиями
decltype(auto) f();
auto f() -> decltype(t.error());
является то, что функция декларация второго может быть недействительным. Возврат типа вычитания для шаблонов функций происходит, когда задано определение [dcl.spec.auto]/12. Хотя я не мог найти ничего о выводе типа возвращаемого значения для функций-членов шаблонов классов, я думаю, что они ведут себя аналогичным образом.
Косвенно инстанцирование шаблона класса Wrapper
приводит к конкретизации из деклараций, но не из определений всех (не виртуальных) функций членов [temp.inst]/1. В заявлении decltype(auto) f();
указан недействительный заполнитель, но он действителен. С другой стороны, auto f() -> decltype(t.error());
имеет недопустимый тип возврата для некоторых экземпляров.
Простым решением в C++ 11 является отсрочка определения типа возврата, например. поворотом f
в шаблон функции:
template<typename U = T>
auto f() -> decltype(std::declval<U&>().error());
Определение этой функции беспокоит меня немного, хотя:
template<typename U = T>
auto f() -> decltype(std::declval<U&>().error())
{
return t.error();
}
Для специализаций Wrapper
где t.error()
не является действительным, выше f
является который не может выдавать действительные специализации. Это может подпадать под [temp.res]/8, в котором говорится, что такие шаблоны плохо сформированный Нет Диагностические Обязательно:
Если действительная специализация не может быть сгенерирована для шаблона, и этот шаблон не создается экземпляр, шаблон плохо сформирован, не требуется диагностика .
Однако, я подозреваю, что правило было введено в позволяют, но не требуют, реализации, чтобы проверить на наличие ошибок, не являющихся инстанцирован шаблонов.В этом случае отсутствует ошибка программирования в исходном коде ; ошибка возникнет при создании экземпляров шаблона класса, описанного в исходном коде. Поэтому я думаю, что все должно быть хорошо.
Альтернативным решением является использование типа запасным возврата, чтобы сделать функцию декларации хорошо сформированным, даже если определение не является (для всех конкретизации):
#include <type_traits>
template<typename T> struct type_is { using type = T; };
template <typename T>
struct Wrapper {
T t;
template<typename U=T, typename=void>
struct error_return_type_or_void : type_is<void> {};
template<typename U>
struct error_return_type_or_void
<U, decltype(std::declval<U&>().error(), void())>
: type_is<decltype(std::declval<U&>().error())> {};
auto f() -> typename error_return_type_or_void<>::type {
return t.error();
}
};
@dyp 'decltype (auto)' был добавлен в C++ 14. – Brian
@Brian Ah, я был введен в заблуждение тегом C++ 14. Должен был читать более внимательно, спасибо. – dyp
Если 't' является публичным элементом данных, почему бы не использовать свободную функцию (шаблон)? – dyp