Как использовать std :: enable_if_t с идеальной пересылкой? - PullRequest
2 голосов
/ 23 февраля 2020

Я написал функцию, получающую переменное c количество std :: пар, которое вычитает 2-й элемент из 1-го элемента каждой пары и возвращает кортеж из вновь сгенерированных результатов, например:

template<typename... pairs, std::enable_if_t<((std::is_same_v<std::pair<int, int>, pairs>) && ...)>* = nullptr>
inline constexpr auto foo(pairs&& ...p) noexcept {
    return std::tuple((std::get<1>(std::forward<pairs>(p)) - std::get<0>(std::forward<pairs>(p)))  ...);
}

int main() {
    constexpr auto bar = foo(std::pair(4, 6), std::pair(3, 7), std::pair(1, 2));

    return 0;
}

Это прекрасно работает. Если я не попытаюсь передать ему std :: pair, который не является rvalue, например:

int main() {
    constexpr auto tup = std::pair(4, 6);
    constexpr auto bar = foo(tup, std::pair(3, 7), std::pair(1, 2));

    return 0;
}

Если я попытаюсь это сделать, я получу следующую ошибку:

no matching function for call to 'foo(const std::pair<int, int>&, std::pair<int, int>, std::pair<int, int>)'

Как я могу передать std :: пар как ссылки на lvalue и rvalue на эту функцию? Я использую C ++ 17

Ответы [ 2 ]

4 голосов
/ 23 февраля 2020

Когда вы передаете Lvalue, pairs будет сохранять ссылку в своем типе, поэтому

std::is_same_v<std::pair<int, int>, pairs>

приводит к ложному.

Вы должны отказаться от ссылки, например, используя std::decay_t :

std::enable_if_t<((std::is_same_v<std::pair<int, int>, std::decay_t<pairs> >) && ...)>* = nullptr
2 голосов
/ 23 февраля 2020

Когда вы передаете функции lvalue , соответствующий ей тип в пакете параметров выводится как ссылка lvalue из-за того, как переадресация ссылок работает. Вы можете использовать std::decay_t для удаления всех ссылок и cv-qualifiers до проверки:

std::enable_if_t<((std::is_same_v<std::pair<int, int>, std::decay_t<pairs>>) && ...)>
...