Используйте аргументы шаблона ссылки во внутреннем классе - PullRequest
1 голос
/ 15 марта 2020

Это мой код:

template<class V, class Ref = V&>
class Util {
public:
    typedef Ref reference;
};

template<class D, class V, class Ref = V&>
class Base {
public:
    class Inner1: public Util<const V, const Ref> {
    public:
        Inner1(const D &d) :
                d(d) {
        }
        typename Inner1::reference foo() const {
            static V v;
            return v;
        }
    private:
        const D &d;
    };
    class Inner2: public Util<V, Ref> {
    public:
        Inner2(D &d) :
                d(d) {
        }
        typename Inner2::reference foo() const {
            static V v;
            return v;
        }
    private:
        D &d;
    };
};

class Child: public Base<Child, float> {
public:
    Inner1 getInner1() const {
        return Base<Child, float>::Inner1(*this);
    }
    Inner2 getInner2() {
        return Base<Child, float>::Inner2(*this);
    }
};

void print(float & ff) {

}

int main() {
    Child c;
    Child::Inner1 inner = c.getInner1();
    print(inner.foo());
    return 0;
}

Этот код компилируется без проблем, но я думаю, что должен получить ошибку компиляции. Метод foo класса Inner1 должен возвращать ссылку const, но по неизвестной причине Ref определен без const. Почему?

Ответы [ 2 ]

2 голосов
/ 15 марта 2020

но по неизвестной причине Ref определяется без конст. Почему?

Ведущий const вводит в заблуждение. В типе Util<const V, const Ref> вы const квалифицируете тип Ref. То есть, вы, вероятно, передаете V & const как тип, а не V const &. Хотя обычно V & const было бы неправильно сформировано, при косвенной работе с типом, например, когда он является псевдонимом или аргументом шаблона, дополнительный квалификатор cv просто игнорируется.

Лично я бы использовал дополнительный Параметр шаблона для всей черты.

template<class V>
class VTrait {
public:
    typedef V & reference;
    typedef V const & const_reference;
};

template<class D, class V, class Trait = VTrait<V>>
class Base {
public:
    class Inner1: public Util<const V, typename Trait::const_reference> {
     // ...
    };

  // ...
};

Клиентскому коду, который хочет что-то отличное от вашей среды, потребуется только настроить Trait.

1 голос
/ 15 марта 2020

const Ref, если Ref равно V&, то есть float&, обратите внимание, что const указывается в самой ссылке, а не в типе ссылки. Квалификатор const просто опущен, вы все равно получаете V&, но не const V&, как вы ожидали. (Если быть точным, в C ++ нет const ссылок , а только ссылок на const или на non- const.)

Если вы измените const Ref на const V& (то есть ссылку на const), вы получите ожидаемую ошибку. например,

class Inner1: public Util<const V, const V&> {
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...