лязг не вывести аргумент шаблона в шаблон функции с переменным числом с 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.


Какой компилятор прав?

622   1  

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

    Ничего не найдено.