Как Boost можно использовать для получения типов автоматического возврата в стиле С++ 14?

Предположим, что у меня есть функция, которая объединяет два значения. Если я ничего не знаю о типах, то в основном я должен написать свою функцию дважды; один раз в действительном возвращаемом значении и снова в качестве спецификатора типа возврата:

template <typename A, typename B>
auto Add(const A& a, const B& b) ->std::decay<decltype(a + b)>::type
{
  return a + b;
}

Пока это работает, это нежелательно, потому что его трудно читать и трудно поддерживать.

В С++ 14 это не будет проблемой, потому что мы можем удалить спецификатор типа возвращаемого значения (я не уверен, что это сделает распад, хотя...). Пока что я застрял с С++ 11.

По моему опыту, когда я ищу функцию на С++, которая еще не пробилась в стандарт, но для которой существует очевидная потребность, Boost library обычно имеет решение. Я просмотрел документацию, но я не нашел ничего, что могло бы мне помочь. Функции BOOST_AUTO_RETURN и BOOST_TYPEOF_TPL кажутся более нацеленными на предоставление возможностей С++ 11 пользователям С++ 03.

В основном, что мне нужно, это то, что выполняет следующие функции:

template <typename A, typename B>
auto Add(const A& a, const B& b)
{
  return a + b; // Deduce return type from this, like C++14 would
}

Есть ли какая-то функциональность в библиотеке Boost, о которой я не знаю (или отличный трюк в С++ 11), который может позволить мне отказаться от явного -> decltype(...) после каждого типа автоматического возврата? Как это будет реализовано?

Ответ 1

Единственный возможный тип возвращаемой функции возврата в С++ 11 - это возвращаемый тип лямбда. Однако С++ 11 ограничивает использование лямбда. Это работает:

auto add = [](int a, int b) { return a + b; };

Это допустимо и определяет add как лямбда, которая определяет функцию-член operator(), которая возвращает int. Поскольку лямбда ничего не захватывает, вы даже можете написать

auto add = +[](int a, int b) { return a + b; };

чтобы сделать add регулярным указателем на функцию: он получает тип int(*)(int, int).

Однако С++ 11 не позволяет указывать типы параметров как auto или не допускать, чтобы add определялось как переменная шаблона, поэтому вы не можете использовать это, чтобы в общем случае выводить тип возвращаемого значения. Попытка обернуть его в класс шаблона не удалась:

template <typename A, typename B>
struct S { static auto add = [](A a, B b) { return a + b; }; }; // invalid

Недопустимо инициализировать add в классе, и вы не можете использовать auto, если член не инициализирован в классе. Кроме того, даже если бы это сработало, это не позволило бы вычесть A или B, что, похоже, больше того, что вам нужно.

Учитывая эти ограничения, я не вижу альтернативы, кроме как повторять выражение. Однако вы можете скрыть повторение в тривиальном макросе.

#define AUTO_RETURN(func, ...) auto func -> decltype(__VA_ARGS__) { return __VA_ARGS__; }

template <typename A, typename B>
AUTO_RETURN(add(A a, B b), a + b)

Или вариант, отмеченный Марк Глисс,

#define RETURNS(...) noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; }

template <typename A, typename B>
auto add(A a, B b) RETURNS(a + b)

который выглядит немного чище.

В Boost может быть что-то вроде этого, я не знаю. Несмотря на тривиальность, Boost кажется излишним здесь.

Ответ 2

Существует библиотека Pythy, которая пытается эмулировать этот синтаксис. Однако он будет работать только на clang. Это не работает на gcc из-за этих ошибок здесь и здесь. Они могут быть исправлены для gcc 4.9, но если вы используете gcc 4.9, вы можете использовать типы автоматического возврата, в любом случае.