Вывод аргументов шаблона для пакета параметров функции, за которым следуют другие параметры

Является ли вычет для f1 и f2 неправильно?

template<class... T, class U>
void f1(T..., U){}

template<class... T>
void f2(T..., int){}

int main()
{
    f1(1);
    f2(1);
    return 0;
}

g ++ принимает оба, clang принимает только f2, а msvc отклоняет оба.

Соответствующая стандартная формулировка:

[temp.deduct.call]

Когда пакет параметров функции появляется в невыведенном контексте ([temp.deduct.type]), тип этого пакета параметров никогда не выводится.

[temp.deduct.type] p5

Невыведенные контексты:

  • Пакет параметров функции, который не находится в конце списка-объявления-параметра.

Так кажется, MSVC правильно отвергает и то, и другое?

Означает ли это, что создание экземпляров шаблонов будет некорректным, даже если вы укажете аргументы шаблона явно?

f1<int>(1, 2); // ill-formed?
f2<int>(1, 2); // ill-formed?

Если это так, зачем вообще допускать такие декларации?


person Jamboree    schedule 15.04.2016    source источник


Ответы (2)


Есть DR для этой конкретной проблемы DR1388. Похоже, что GCC и CLANG еще не реализовали его CLANG DR1388.

Означает ли это, что создание экземпляров шаблонов будет некорректным, даже если вы укажете аргументы шаблона явно?

f1<int>(1, 2); // ill-formed?
f2<int>(1, 2); // ill-formed?

Если это так, зачем вообще допускать такие декларации?

Нет, если вы явно укажете аргументы шаблона, вычетов не произойдет, и, как таковой, приведенный выше код является допустимым.

person 101010    schedule 15.04.2016
comment
Я думаю, что разрешение все еще ошибочно - пакет параметров концептуально бесконечен, вы не можете явно указать все аргументы, это означает, что всегда нужно выводить параметры, и поскольку он находится в невыведенном контекст, остальная часть пакета параметров никогда не выводится. - person Jamboree; 15.04.2016
comment
@Jamboree Вы сами сказали, что это невыведенный контекст, однако, если вы явно укажете аргументы пакета, никакого вывода не произойдет. - person 101010; 15.04.2016
comment
Считаются ли они явно указанными: f1<>(1); f2<>(1);? <> имеет ли здесь значение? - person Jamboree; 15.04.2016
comment
<> - это пустой список аргументов, но это список аргументов. Пакет будет преобразован в пустой пакет. - person 101010; 15.04.2016
comment
Так вы предполагаете, что f1(1) неправильно сформирован, а f1<>(1) в порядке? - person Jamboree; 15.04.2016
comment
После просмотра DR1399 становится ясно, что оба f1(1) и f1<>(1) должны быть в порядке, поэтому GCC в этом отношении прав. - person Jamboree; 15.04.2016
comment
@Jamboree DR1399: эта проблема устранена решением проблемы 1388. - person 101010; 15.04.2016
comment
Если бы вы могли обновить свой ответ, чтобы прояснить, что все мои примеры правильно сформированы и GCC является правильным, я могу принять этот ответ и удалить приведенное выше обсуждение. - person Jamboree; 15.04.2016

Я сам изучил этот точный вопрос, и мне было на удивление сложно получить четкий ответ. Насколько я могу судить, f1(1) следует отклонить, но f2(1) следует принять.

При этом сказано:

  • clang ++ - 5.0 принимает оба
  • g ++ - 6 принимает оба
  • EDG 4.14 отклоняет оба

Как вы отметили, пакет параметров функции, который не находится в конце списка, является невыведенным контекстом ([temp.deduct.type] p5):

Невыведенные контексты:

  • ...
  • Пакет параметров функции, который не находится в конце списка-объявления-параметра.

и [temp.deduct.call] p1 (изменено через CWG 1388) поясняет, что такой пакет параметров никогда не выводится.

Когда пакет параметров функции появляется в невыведенном контексте, тип этого пакета параметров никогда не выводится.

Кроме того, [temp.arg.explicit] p3 указывает:

Завершающий пакет параметров шаблона (14.5.3), не выведенный иным образом, будет выведен в пустую последовательность аргументов шаблона.

Итак, принимая во внимание это для вызова f2(1): пакет T является завершающим пакетом параметров шаблона (хотя он не является завершающим пакетом параметров функции), поэтому он выводится как пустая пачка и звонок действителен.

Однако для f1(1) пакет T также не является завершающим пакетом параметров шаблона, потому что за ним следует U, поэтому он не считается пустым пакетом на [temp.arg.explicit] p3. Следовательно, поскольку пакет параметров шаблона T не может быть выведен для вызова f1(1), он не должен участвовать в разрешении перегрузки, и вызов должен завершиться ошибкой.


Обратите внимание, что несколько похожих вопросов / примеров были подняты в других обсуждениях, но все они несколько отличаются:

  • Вызов f(0) в примере кода CWG 1388 и CWG 1399 действительна, потому что рассматриваемый пакет является завершающим пакетом параметров шаблона, поэтому он относится к случаю, о котором я упоминал выше. Вот код из CWG 1399:
    template <class... T>
    void f(T..., int, T...) { }
    
    int main() {
      f(0);          // OK
      f<int>(0,0,0); // OK
      f(0,0,0);      // error
    }
    
  • Пример кода при обсуждении ошибки 21774 LLVM аналогичен CWG 1399. Например, пакет является завершающим пакетом параметров шаблона. То же самое и с этим вопросом.
  • CWG 2055, которая не решена, касается на аналогичном тестовом примере. Когда эта проблема будет решена, ее решение, скорее всего, прольет свет на правильное поведение примеров в этом вопросе. Вот проблема, упомянутая в CWG 2055:
    # P12 #
    template<typename... T> void f(typename T::type...)   {
    }
    
    int main() {
      f<>();
    }
    
person Chris Badger    schedule 26.01.2018