Как найти по ключу константного указателя в карте с неконстантными ключами указателя - PullRequest
0 голосов
/ 08 февраля 2019

Следующий код C ++ не компилируется, поскольку он передает неконстантный указатель в функцию find(), которая ожидает константный указатель.

#include <map>

std::map<int*, double> mymap;

double myfind(const int * mykey)
{
    return mymap.find(mykey)->second;
}

Есть ли способ заставить поиск работать безизменить тип карты или сделать переменную mykey неконстантной?Ведь функция find() не изменяет указанный объект, она просто сравнивает указатели.

Ответы [ 4 ]

0 голосов
/ 11 февраля 2019

Я думаю, что нашел решение, но оно требует прозрачных компараторов C ++ 14.

#include <map>
#include <iostream>

struct CompareIntPtrs
{
    using is_transparent = void; // enabling C++14 transparent comparators

    bool operator()(const int * l, const int * r) const
    {
        return l < r;
    }
};

std::map<int*, double, CompareIntPtrs> mymap;

double myfind(const int * key)
{
    return mymap.find(key)->second;
}

int main()
{
    int x {6};
    mymap[&x] = 66; // inserting to the map
    const int * px = &x; // creating a "const int *" variable

    std::cout << myfind(px) << std::endl; // using "const int *" for finding in map with "int*" keys
    std::cout << mymap.find(px)->second << std::endl; // we could even skip using myfind()
}

Отличную статью о прозрачных компараторах C ++ 14 можно найти здесь ,Честно говоря, добавив компаратор, тип mymap немного изменился, чего я изначально не хотел, но это лучшее решение, которое я смог найти.

Если C ++ 14 недоступенЕсть как минимум два зла, из которых мы можем выбрать.Первый - скопировать mymap в новый std::map<const int*, double> в myfind, что ужасно неэффективно.Второй - отбрасывание константности с использованием const_cast<int*>(mykey), которого следует избегать , если это возможно.

0 голосов
/ 08 февраля 2019

Ключ на карте является семантически неизменным, все операции на карте, которые позволяют прямой доступ к ключам, делают это путем const -квалификации типа ключа (например, value_type определяется как pair<const Key, T>).

В случае int* типа ключа вы получите const указатель на неконстантный int (int*const), что не очень хорошо (все еще работает, так какв качестве ключа используется только указатель значение , но семантика неизменности становится разбавленной, что может привести к ошибкам).

Вместо того, чтобы отбрасывать константу, просто измените map наmap<const int*, double>.

Тогда он будет работать как для const int*, так и для int* клавиш.

#include <map>

std::map<const int*, double> mymap;

double myfind(const int * mykey)
{
    return mymap.find(mykey)->second; // just works
}

double myfind(int * mykey)
{
    return mymap.find(mykey)->second; // also works
}
0 голосов
/ 08 февраля 2019

У вас может быть проблема с правильностью.const int * может быть не тем, что вы думаете .Это указатель на константу целое число .Это не то же самое, что тип ключа вашей карты, который является указателем на (непостоянное) целое число .И ни то, ни другое не совпадает с int * const, который является константным указателем на (непостоянное) целое число .Вопрос не в том, является ли само значение ключа изменчивым или неизменным, а в том, являются ли изменяемые или неизменяемые объекты, на которые вы храните указатели,

Например, такими компиляциями:

std::map<int *, double> mymap;
double myfind(int * const mykey) {
    return mymap.find(mykey)->second;
}

Как это сделать:

std::map<const int *, double> mymap;
double myfind(const int *mykey) {
    return mymap.find(mykey)->second;
}
double myfind2(const int * const mykey) {
    return mymap.find(mykey)->second;
}

Вы видите разницу?В вашем исходном коде компилятор совершенно правильно отмечает ошибку.Если ваша функция принимает const int *, то вы фактически обещаете не изменять int, на который указывает указатель, который я передаю. Но если вы используете такой указатель, как int * в ключе std::map, вы можете позволить кому-то изменить это int.

В этом конкретном случае мы знаем, что std::map::find() не будет назначать аргумент-указатель, но компилятор этого не делает, поэтому const_cast<> существует, как указано в других ответах.

0 голосов
/ 08 февраля 2019

Попробуйте const_cast, что позволяет изменять постоянство (или изменчивость) переменной.

#include <map>

std::map<int*, double> mymap;

double myfind(const int * mykey)
{
    return mymap.find(const_cast<int*>(mykey))->second;
}
...