Противоречивые возвращаемые типы итераторов std::set

Это вторая ошибка компилятора сегодня, которая запутала меня. Так или иначе для кода ниже, gcc жалуется, что в коде есть функция, которая возвращает итератор return_iter возвращать конфликтующие типы std::_Rb_tree_iterator<const int*> а потом std::_Rb_tree_const_iterator<const int*>, но оба они не должны быть константными итераторами, потому что множество не является константным. Может ли кто-нибудь объяснить, почему std::end() метод при вызове неконстантного lvalue возвращает const_iterator?

Полный код вставлен ниже.

Обратите внимание, я получаю эту ошибку только при компиляции с gcc, Эта ошибка не отображается при компиляции с помощью clang (Apple LLVM version 8.0.0 (clang-800.0.38), Я использую версию gcc g++ (GCC) 5.1.0

Смежный вопрос. Это правильное использование форварда? Считается ли нормально звонить std::forward когда вы хотите использовать ссылку для пересылки? Причина, по которой я вызвал ее ниже, заключается в том, что тип перегружает некоторые методы, когда объект является значением.


#include <vector>
#include <string>
#include <set>
#include <iostream>
using namespace std;

int global_value = 1;

class LessPtr {
public:

    template <typename PointerComparableOne, typename PointerComparableTwo>
    constexpr auto operator()(PointerComparableOne&& lhs,
                              PointerComparableTwo&& rhs) const {
        return *std::forward<PointerComparableOne>(lhs) <
            *std::forward<PointerComparableTwo>(rhs);
    }

    using is_transparent = std::less<void>::is_transparent;
};

template <typename Container, typename Key>
auto return_iter(Container&& container, Key&& key) {
    if (global_value == 1) {
        return std::forward<Container>(container).lower_bound(std::forward<Key>(key));
    }
    else {
        return std::end(std::forward<Container>(container));
    }
}

void do_stuff(std::set<const int*, LessPtr>& set_ptrs) {
    // auto value = string{"something"};
    auto value = 1;
    auto iter = return_iter(set_ptrs, &value);
    cout << reinterpret_cast<void*>(&iter) << endl;
}

int main() {
    std::set<const int*, LessPtr> set_ptrs;
    do_stuff(set_ptrs);

    return 0;
}

LessPtr как-то нужно вызвать эту ошибку..

1 ответ

Это ошибка libstdC++ в пути std::set обрабатывает прозрачные компараторы. Вот более короткий пример:

int main() {
    using S = std::set<const int*, LessPtr>;
    S set_ptrs;

    int i = 0;
    const int ci = 0;
    static_assert(std::is_same<
          decltype(set_ptrs.lower_bound(&ci)), S::iterator>{}, "!"); // OK
    static_assert(std::is_same<
          decltype(set_ptrs.lower_bound(&i)), S::iterator>{}, "!");  // Error

    return 0;
}

Первое утверждение в порядке, мы называем lower_bound(Key const&), который возвращает iterator, Второе утверждение срабатывает, потому что мы вызываем шаблон функции template <class K> lower_bound(K const&), так как LessPtr является прозрачным, и эта перегрузка является лучшим соответствием (потому что это точное соответствие), и эта, для libstdC++, возвращает const_iterator,

Но set_ptrs не constтак не должно быть. Я подал 78134

Другие вопросы по тегам