Шаблон вычета, это соответствует? - PullRequest
0 голосов
/ 09 ноября 2018

Кажется, что этот код неверен, так как я получаю за это ошибки компилятора. Я пытаюсь понять, почему:

template <class ... Ts>
struct type_list{};

template <class ... Ts, class T_, class ... Ts_>
auto foo(type_list<Ts...>, Ts&&..., T_&&t, Ts_&&...) {
    return sizeof(T_);
}

int main() {
  std::cerr << foo(type_list<int>{}, 5, 5.0, 3);
  return 0;
}

clang выдает следующую ошибку:

example.cpp:16:16: error: no matching function for call to 'foo'
  std::cerr << foo(type_list<int>{}, 5, 5.0, 3);
               ^~~
example.cpp:11:6: note: candidate template ignored: deduced conflicting types for parameter 'Ts'
      (<int> vs. <>)
auto foo(type_list<Ts...>, Ts&&..., T_&&t, Ts_&&...) {

Мне кажется, что в моем вызове Ts должно быть выведено на int (так как это единственный способ заставить первый аргумент работать), и тогда все остальное будет принудительно выполнено. Почему это не работает?

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

C ++ не использует все возможности и не находит единственно допустимого.Он следует очень конкретным правилам, и если эти правила не работают, он генерирует ошибку.

В общем случае выводимый пакет ... должен быть последним, если он выводится.Попытки обойти это не удастся.

Вот решение, позволяющее избежать вашей проблемы:

template <class ... Ts, class...Us>
auto foo(type_list<Ts...>, Us&&...us) {
    return [](Ts&&...ts, auto&& t, auto&&...) {
        return sizeof(t);
    }(std::forward<Us>(us)...);
}

int main() {
  std::cerr << foo(type_list<int>{}, 5, 5.0, 3);
  return 0;
}
0 голосов
/ 09 ноября 2018

Clang выводит Ts из двух конфликтующих источников: type_list<Ts...> и Ts&&.... Поскольку вы звоните foo с type_list<int>{}, Ts сначала выводится как {int}. Однако, поскольку последний аргумент Ts_&&... имеет тип пакета параметров, он перехватывает все, что может; в этом случае два последних аргумента (в то время как T_&&t передается 5), что выводит Ts_ как {double, int}T_ как int). Это оставляет Ts без аргументов, поэтому выводится как {}.

Следовательно, сообщение об ошибке Clang: Ts выводится как {} и {int} ((<int> vs. <>) в сообщении об ошибке).

Обратите внимание, что GCC работает по-другому:

ошибка: слишком мало аргументов для функции 'auto foo (type_list, Ts && ..., T _ &&, Ts _ && ...) [with Ts = {int}; T_ = int; Ts_ = {double, int}] '

Он пытается сохранить Ts как {int}, но все равно выводит Ts_ как {double, int}, и поэтому нет способа дать правильное количество аргументов.

Чтобы объяснить немного подробнее, рассмотрим следующее:

template <class ... Ts>
struct type_list{};

template <class ... Ts>
auto foo(type_list<Ts...>, Ts...) {
    return sizeof...(Ts);
}

int main() {
  std::cerr << foo(type_list<int>{}, 5, 5.0, 3);
}

Clang правильно вызывает это, потому что два вывода противоречивы:

примечание: шаблон кандидата игнорируется: выводит конфликтующие типы для параметра 'Ts' (<int> против <int, double, int>)

Проблема в том, что вы не можете поймать 2 аргумента с другим пакетом параметров, потому что он либо поймает все, если будет помещено после (как в вашем случае), либо ничего, если будет помещено до:

template <class ... Ts>
struct type_list{};

template <class... Ts, class... Ts_>
auto foo(type_list<Ts...>, Ts_..., Ts...) {
    return sizeof...(Ts);
}

int main() {
  std::cerr << foo(type_list<int>{}, 5, 5.0, 3);
}

Здесь Clang выдает то же сообщение об ошибке, поскольку Ts по-прежнему выводится как {int} из type_list и {int, double, int} путем перехвата всех оставшихся аргументов.

Я думаю, что ваш единственный выбор - как-то иметь дело с кортежами или быть более явным с помощью вызова: foo<int>(type_list<int>{}, 5, 5.0, 3) (и вы, вероятно, можете удалить type_list в этом случае). Таким образом, Ts больше не выводится: вы явно делаете это {int}.

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