Неявная инстанциация не определенного шаблона std::tuple_element

Вопрос или проблема

Фрагмент, также на godbolt

#include <tuple>
#include <utility>

template <typename Tuple, std::size_t... Ints>
auto select_tuple(Tuple&& tuple, std::index_sequence<Ints...>) {
    return std::tuple<std::tuple_element_t<Ints, Tuple>...>(
        std::get<Ints>(std::forward<Tuple>(tuple))...);
}

int main() {
    std::tuple<int, char, float> t{1, 'x', 2.0};
    auto t2 = select_tuple(t, std::index_sequence<0, 2>{});
}

Как видно по ссылке godbolt, компилятор выдает ошибку:

/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../include/c++/15.0.0/bits/utility.h:135:5: ошибка: неявная инстанция неопределенного шаблона 'std::tuple_element<0, std::tuple<int, char, float> &>'
  135 |     using tuple_element_t = typename tuple_element<__i, _Tp>::type;

Компилятор считает, что не знает std::tuple_element, но tuple включен.
Что здесь не так?

На самом деле у вас есть std::tuple_element_t<0, std::tuple<int, char, float>&> (обратите внимание на ссылку),
вам нужно удалить ссылку (и квалификаторы cv) в трейтах:

template <typename Tuple, std::size_t... Ints>
auto select_tuple(Tuple&& tuple, std::index_sequence<Ints...>) {
    return std::tuple<std::tuple_element_t<Ints, std::decay_t<Tuple>>...>(
        std::get<Ints>(std::forward<Tuple>(tuple))...);
}

Демонстрация

Ответ или решение

Ошибка компиляции с сообщением об "implicit instantiation of undefined template std::tuple_element" возникает из-за неправильного использования std::tuple_element_t в вашем коде, связанного с передачей ссылки на кортеж.

При использовании std::tuple_element_t необходима передача типа кортежа без ссылок и константных квалификаторов. Поэтому, когда вы пишете std::tuple_element_t<Ints, Tuple&>, это приводит к ошибке компиляции, потому что std::tuple_element ожидает тип без указателей и ссылок.

Для решения проблемы необходимо применить std::decay_t к типу кортежа, который убирает ссылки и константные квалификаторы. Измените код следующим образом:

#include <tuple>
#include <utility>

template <typename Tuple, std::size_t... Ints>
auto select_tuple(Tuple&& tuple, std::index_sequence<Ints...>) {
    return std::tuple<std::tuple_element_t<Ints, std::decay_t<Tuple>>...>(
        std::get<Ints>(std::forward<Tuple>(tuple))...);
}

int main() {
    std::tuple<int, char, float> t{1, 'x', 2.0};
    auto t2 = select_tuple(t, std::index_sequence<0, 2>{});
}

В этом исправленном коде мы используем std::decay_t<Tuple>, чтобы получить обрезанный тип кортежа, что позволяет std::tuple_element корректно инстанцироваться и избегать ошибки компиляции.

Демонстрация исправленного кода доступна по следующей ссылке: Demo.

Таким образом, основная проблема заключалась в том, что передавался тип с ссылкой в шаблон std::tuple_element_t. Убедитесь, что вы используете std::decay_t, чтобы избежать этой проблемы.

Оцените материал
Добавить комментарий

Капча загружается...