руководства по удержанию и введенные имена классов - PullRequest
0 голосов
/ 03 июля 2018
template <typename T>
struct X
{
    template <typename Iter>
    X(Iter a, Iter b) {}

    template <typename Iter>
    auto f(Iter a, Iter b)
    {
        return X(a, b);
    }
};

В "Шаблоны C ++, Полное руководство" 2-е издание был предыдущий пример с субтитрами неявных руководств по выводам с введенными именами классов. Автор упомянул, что вывод аргументов класса отключен для введенных имен классов, потому что тип возврата f будет X<Iter> из-за неявного руководства по выводу. Но я полагаю, что неявное руководство по выводу для конструктора шаблона скорее будет похоже на приведенное ниже.

  template <typename T, typename Iter>
  X(Iter a, Iter b) -> X<T>;

Мой вопрос заключается в том, как бы выводить типы аргументов шаблона класса в этом случае T и Iter - это два разных типа, а типы параметров зависят только от Iter. Кроме того, даже если T можно как-то вывести, T и Iter независимы, поэтому вывод Iter из аргументов не должен означать, что X имеет тип X<Iter> верно? Это какая-то ошибка с текстом в книге, или руководство по выводам должно выглядеть иначе, чем я думал?

1 Ответ

0 голосов
/ 03 июля 2018

Вы правы. Неявно сгенерированное руководство по выводам действительно будет похоже на то, которое вы написали. И вывод аргумента шаблона никогда не сможет вывести T из него. Это действительно не вызовет проблем. Проблема заключается в предоставленных пользователем руководствах по выводам. Как это:

template <typename Iter>
X(Iter a, Iter b) -> X<typename Iter::value_type>;

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

Вот иллюстрация проблемы:

auto v = std::vector<int>{1, 2};
auto x1 = X<float>(begin(v), end(v));
auto x2 = x1.f(begin(v), begin(v));

Какой тип x2? Если мы прочитаем определение шаблона класса, мы ожидаем, что оно будет X<float>, как это было бы в C ++ 14, но если вычет аргумента шаблона класса не отключен, и мы добавим наше руководство по выводу, мы получим X<int>!

Представьте себе существующие базы кода, в которых типы внезапно сместились после перехода на C ++ 17. Это было бы очень плохо.

...