C ++ variadic шаблоны различных типов ввода с использованием c ++ 11 - PullRequest
0 голосов
/ 07 мая 2018

В последнее время я занимаюсь исследованием современного c ++. Я видел видео [в 49:00] о вариативных шаблонах c ++ 11 / c ++ 14. Если вы хотите вычислить сумму кортежа различных типов (таких как int, double) с помощью шаблонов с вариационными данными, используя c ++ 11, видео предлагает решение:

struct Sum
{
    template<typename T>
    static T sum(T n)
    {
        return n;
    }

    template<typename T, typename... Args>
    static auto sum(T n, Args... rest) -> decltype(n+sum(rest...))
    {
        return n + sum(rest...);
    }
}
auto x = Sum::sum(1, 2.5, 3);

auto не может вывести тип возвращаемого значения в c++11, поэтому вы должны объявить тип возвращаемого значения, используя decltype. Но сборка компилятора не удалась, сборка компилятора прошла успешно. ссылка

Хотя использование auto to deduce return type не имеет проблем, мой вопрос:

  1. Стандарт c++11 охватывает этот вопрос? Если нет, решают ли компиляторы проблему с помощью собственной реализации?
  2. Почему не удалось скомпилировать новейшую версию gcc 8.1, а gcc 4/5/6/7 скомпилировать успешно? Есть ли проблема с совместимостью в gcc?

Кстати, сообщение об ошибке компиляции:

test.cc: 20: 16: ошибка: нет соответствующей функции для вызова 'sum'

 double x = Sum::sum(1, 2.5, 3);

test.cc: 12: 17: примечание: шаблон кандидата игнорируется: ошибка замещения [с T = int, Args =]: использование необъявленного идентификатора 'sum'

 static auto sum(T n, Args... rest) -> decltype(n + sum(rest...))

test.cc: 6: 14: примечание: шаблон функции-кандидата недопустим: требуется один аргумент 'n', но было предоставлено 3 аргумента

static T sum(T n)

1 сгенерированная ошибка.

1 Ответ

0 голосов
/ 07 мая 2018

Поиск имени функции в конце типа возврата здесь,

template<typename T, typename... Args>
static auto sum(T n, Args... rest) -> decltype(n+sum(rest...))

выполняется в контексте непосредственно перед объявлением этого sum, плюс через ADL (поиск в зависимости от аргумента).

И так как этот шаблон не виден через ADL в момент вызова для рассматриваемых типов, вполне допустимо, чтобы он не компилировался.

Старые компиляторы gcc, вероятно, использовали контекст объекта в дополнение к контекстам, которые они должны. Это разумная ошибка.

Вы можете легко это исправить:

struct Sum {
private:
  template<typename T>
  friend T summer(Sum, T n) {
    return n;
  }
  template<typename T, typename... Args>
  friend auto summer(Sum, T n, Args... rest) -> decltype(n+summer(Sum{},rest...)) {
    return n + summer(Sum{},rest...);
  }
public:
  template<class...Args>
  auto sum(Args...args)->decltype(summer(Sum{}, args...)){
    return summer(Sum{}, args... );
  }
};

здесь мы навязываем ADL некоторым личным друзьям. Это позволяет летним перегрузкам «видеть себя» в их типе конечного возврата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...