Rvalue разница перегрузки между clang и gcc - PullRequest
0 голосов
/ 19 января 2019

Я реализую функцию карты с двумя перегрузками: одна для rvalues ​​и другая для константной ссылки:

template <class Array, class UnaryOp>
void map_inplace(UnaryOp op, Array &a) {
    std::transform(a.cbegin(), a.cend(), a.begin(), op);
}

template <class Array, class UnaryOp>
auto map(UnaryOp op, Array &&a) {
    map_inplace(op, a);
    return a;
}

template <class Array, class UnaryOp>
auto map(UnaryOp op, const Array &a) {
    Array res(a);
    map_inplace(op, res);
    return res;
}

И у меня есть следующий тест:

TEST_CASE("map") {
    const std::vector v{1., 2., 3.};

    // I do expect the const reference overload to be called
    REQUIRE(almost_equal(map(std::negate<>(), v), {-1., -2., -3.}));

    // Check const vector is not modified
    REQUIRE(v == std::vector{1., 2., 3.});
}

Запустив его с Clang, тестовый проход:

пройден: почти_эквивалент (map (std :: negate <> (), v), {-1., -2., -3.}) Для: true

передано: v == std :: vector {1., 2., 3.} для: {1.0, 2.0, 3.0} == {1.0, 2.0, 3.0}

Пройдено 1 контрольный пример с 2 утверждениями.

Но с GCC ничего не получается:

пройдено: почти_эквивалент (map (std :: negate <> (), v), {-1., -2., -3.}) Для: true

не удалось: v == std :: vector {1., 2., 3.} для: {-1.0, -2.0, -3.0} == {1.0, 2.0, 3.0}

Неудачный тестовый пример 1, неудачное утверждение 1.

Таким образом, GCC вызывает ссылочную перегрузку rvalue и модифицируетопределенный константой вектор.

Версия GCC:

gcc (Ubuntu 7.3.0-27ubuntu1 ~ 18.04) 7.3.0

Версия Clang:

лязг версиина 6.0.0-1ubuntu2 (tags / RELEASE_600 / final)

РЕДАКТИРОВАТЬ:

Итак, я пробовал больше тестов, это не с GCC:

TEST_CASE("map") {
    const std::vector v{1., 2., 3.};
    REQUIRE((map(std::negate<>(), v) == std::vector{-1., -2., -3.}));
    REQUIRE(v == std::vector{1., 2., 3.});
}

Но если я добавлю параметры типа шаблона:

TEST_CASE("map") {
    const std::vector<double> v{1., 2., 3.};
    REQUIRE((map(std::negate<>(), v) == std::vector<double>{-1., -2., -3.}));
    REQUIRE(v == std::vector<double>{1., 2., 3.});
}

, то это сработает!

1 Ответ

0 голосов
/ 19 января 2019

Минимальный пример, демонстрирующий эту проблему:

#include <vector>
#include <type_traits>

const ::std::vector<double> v1{1., 2., 3.};
const ::std::vector v{1., 2., 3.};
static_assert(::std::is_same_v<decltype(v1), decltype(v)>); // error on gcc

онлайн-компилятор

Ошибка 80990 - квалификаторы cv игнорируются в определении переменной с использованием аргумента шаблона классавычет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...