Сделайте метод явным за исключением классов друзей - PullRequest
3 голосов
/ 10 марта 2019

Я пытаюсь создать оператор преобразования, который был бы явным по умолчанию, за исключением некоторых обозначенных классов.

Точнее, у меня есть относительно простой шаблон класса, экземпляры которого должны быть преобразованы в какой-то другой тип (int по всему этому вопросу, для простоты). Тем не менее, я хочу, чтобы это преобразование было явным по умолчанию, но все же позволяло, чтобы оно было неявным для одного другого класса, а именно для класса, передаваемого в качестве аргумента шаблона. Без этой последней части это будет выглядеть так:

template<typename T>
class A {
public:
    A(int i) : i(i) {}
    explicit operator int() const {
        return i;
    }

private:
    int i;
};

Теперь я хочу написать что-то вроде A a(2); int i = a; внутри методов T (который должен быть классом).

Моя первая идея состояла в том, чтобы использовать объявления друзей и объявить частную перегрузку оператора преобразования. Однако перегрузка, основанная исключительно на explicit, не допускается. Поэтому я попытался использовать const вместо этого, и это сработало:

template<typename T>
class A {
public:
    A(int i) : i(i) {}
    explicit operator int() { // Public non-const
        return i;
    }

private:
    int i;

    operator int() const { // Private const
        return i;
    }

    friend T;
};

... пока это не так. Это работает только при использовании неконстантных A с, и хотя я не планирую использовать const A с, я все же хотел бы, чтобы оно работало во всех случаях. Обратите внимание, что если общая перегрузка const, а частная перегрузка - нет, это работает только с использованием const A s.

Вот демонстрационная версия , показывающая, в каких случаях она работает или нет.

Я думал об использовании volatile ( demo ), и хотя это делает его лучше, оно все равно приводит к той же проблеме: оно работает только при использовании энергонезависимых A s.

Есть ли лучший способ сделать это? В более общем смысле, есть ли способ решить проблему в самом первом предложении?

1 Ответ

1 голос
/ 12 марта 2019

По-видимому, нет удовлетворительного решения.Опция volatile представляется наиболее практичной, и хотя она не вполне работает с volatile A s, дополнительная const_cast решает эту проблему.

template<typename T>
class A {
public:
    A(int i) : i(i) {}
    explicit operator int() const {
        return i;
    }

private:
    int i;

    operator int() const volatile {
        return static_cast<int>(const_cast<A const&>(*this));
        // or just
        // return i;
    }

    friend T;
};

Демо

Как заявил Снефтел в комментариях, разрешения на доступ, как правило, предоставляются на основе извлечения (using), а не на основе подталкивания.Возможно, поэтому язык не позволяет изменять семантику преобразования в зависимости от класса или блока, выполняющего преобразования.

...