Компилятор C ++ выбирает неправильную перегрузку функции-члена класса - PullRequest
1 голос
/ 16 августа 2011

У меня есть этот код:

template <class T>
class Something
{
    T val;
public:
    inline Something() : val() {}
    inline Something(T v) : val(v) {}
    inline T& get() const { return val; }

    inline Something& operator =(const Something& a) { val = a.val; return *this; }
};

typedef Something<int> IntSomething;
typedef Something<const int> ConstIntSomething;

class Other
{
public:
    IntSomething some_function()
    {
        return IntSomething(42);
    }

    ConstIntSomething some_function() const
    {
        return ConstIntSomething(42);
    }
};

void wtf_func()
{
    Other o;
    ConstIntSomething s;
    s = o.some_function();
}

Однако компилятор выбирает неправильную перегрузку Other::some_function() в wtf_func() (т.е. неконстантную).Как я могу это исправить?Обратите внимание, что по определенным причинам я не могу изменить имя Other::some_function().

Ответы [ 5 ]

2 голосов
/ 16 августа 2011

o не является константной, поэтому выбирается неконстантная some_function.Если вы хотите выбрать перегрузку с квалификацией const, вам необходимо добавить квалификатор const к o:

Other o;
Other const& oref(o);
ConstIntSomething s;
s = oref.some_function();

Когда происходит разрешение перегрузки, компилятор просматривает только подвыражение o.some_function();он не смотрит на контекст вокруг вызова функции, чтобы решить выбрать что-то еще.Кроме того, возвращаемый тип функции-члена не учитывается при разрешении перегрузки.

Обратите внимание, что для IntSomething может иметь смысл быть неявно преобразованным в ConstIntSomething, либо используя перегрузку operator ConstIntSomething() вIntSomething (менее хорошо) или использование неявного конструктора ConstIntSomething(IntSomething const&) в ConstIntSomething (более хорошо).

1 голос
/ 16 августа 2011

Ваш объект o должен быть const объектом для вызова const функции. В противном случае компилятор правильно выбирает неконстантную версию функции.

1 голос
/ 16 августа 2011

Это не выбирает неправильную перегрузку; const -ness определяется тем, является ли this 1003 * или нет. В вашем случае, o не является const, поэтому перегрузка не const выбрана.

Вы можете взломать это, создав const-ссылку на o, например ::

const Other &o2 = o;
s = o2.some_function();

Но на самом деле, вы, вероятно, должны учитывать ваши перегрузки в Something. Например, в настоящее время вы не можете сделать это:

IntSomething x;
ConstIntSomething y;
y = x;

что не звучит правильно. Почему бы вам не разрешить принимать константные ссылки на неконстантные ссылки?

0 голосов
/ 16 августа 2011

Вы также можете скопировать новое поведение, обнаруженное в контейнерах стандартной библиотеки C ++ 0x. Контейнеры, такие как vector, теперь имеют члены cbegin() и cend(), которые возвращают const_iterator независимо от того, является ли контейнер постоянным или нет, в отличие от begin() и end()

class Other {
    // Rest of other
public:
    // No overload for non-const
    // Even if called with a non const Other, since this member is marked
    // const, this will be of type Other const * in all cases and will call
    // the const qualified overload of some_function.
    ConstIntSomething csome_function() const
    {
        return some_function();
    }
};
0 голосов
/ 16 августа 2011

Компилятор выбирает используемую перегрузку на основе константности объекта, который станет this.Вы можете вызвать нужную версию с помощью static_cast: s = static_cast<const Other&>(o.some_function());

...