лязг не вывести аргумент шаблона в шаблон функции с переменным числом с varargs
Рассмотрим код:
#include <tuple>
template<class... Args, class T>
T method(std::tuple<Args...>, Args..., T, ...) {
return T();
}
int main() {
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
1, 1.0f, 1.0, 1);
}
g++ так как 4.9 не имеет проблем с его компиляцией. clang++ с другой стороны дает ошибку:
main.cpp:9:5: error: no matching function for call to 'method'
method(std::make_tuple<int, float, double>(1, 1.0f, 1.0),
^~~~~~
main.cpp:4:3: note: candidate template ignored: couldn't infer template argument 'T'
T method(std::tuple<Args...>, Args..., T, ...) {
^
1 error generated.
Какой компилятор прав?
1 ответ:
Код плохо сформирован. Оба компилятора корректно не компилируют:
#include <tuple> template<class... Args, class T> T method(std::tuple<Args...>, Args..., T) { return T(); } int main() { method(std::make_tuple<int, float, double>(1, 1.0f, 1.0), 1, 1.0f, 1.0, 1); }У нас есть, от [temp.вычитать.call], Курсив мой:
Когда пакет параметров функции появляется в неразведенном контексте (14.8.2.5), тип этого пакета параметров никогда не выводится.
Args...появляется в недифференцированном контексте, потому что из [temp.вычитать.тип]:Таким образом, по точной формулировке стандарта,Недедуцированные контексты: [...] Пакет параметров функции, который не встречаются в конце спискаparameter-declaration-list .
Args...не должно быть выведено, поэтому вы должны явно предоставить его - что в данном случае все еще не представляется возможным должным образомT.Но в этом случае
Args...появляется как в дедуцированном, так и в недедуцированном контексте-ничто не должно препятствоватьArgs...быть выведено из аргументаtupleкак{int, float, double}, а затем просто повторно использовать это выведение для вариадические аргументы, а затем выводитьTкакintв конце.но этот предлагаемый процесс будет конфликтовать с типичным процессом дедукции, где мы обрабатываем каждую пару параметров/аргументов независимо. В этом случае дедукция по
Tочень сильно зависит от дедукции поArgs...из парыtuple<>параметр/аргумент.Если вы просто перевернете порядок:
template <class... Args, class T> T method(std::tuple<Args...>, T, Args...) { ... }Затем оба компилятора компилируют его.
Я понятия не имею, почему gcc принимает оригинал пример с varargs. Это явно неправильно.
Кроме того, если вы перевернете спецификацию параметров шаблона так, чтобы можно было указать
T, не требуя вычитания, то clang принимает, но gcc отклоняет:Я ожидал бы, что это будет хорошо сформировано -template<class T, class... Args> T method(std::tuple<Args...>, Args..., T) { return T(); } int main() { method<int>(std::make_tuple<int>(1), 1, 1); }Args...можно вывести иTне обязательно. Поэтому формулировка "никогда не выводил", на мой взгляд, сомнительна.
Comments