greywolf82
greywolf82

Reputation: 22183

Use reference template arguments in inner class

This is my code:

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;
}

This code compile without problems but I guess I should receive a compilation error. The method foo of class Inner1 should return a const reference, but for unknown reason Ref is defined without const. Why?

Upvotes: 1

Views: 52

Answers (2)

but for unknown reason Ref is defined without const. Why?

Leading const is misleading. In the type Util<const V, const Ref> you const qualify the Ref type. I.e., you supposedly pass V & const as the type, and not V const &. While normally V & const would be ill-formed, when dealing with the type indirectly, such as when it's aliased or a template argument, the extra cv-qualifier is simply ignored.

Personally, I would use the extra template parameter for an entire trait.

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> {
     // ...
    };

  // ...
};

Client code that wants something different from your framework will need only customize the Trait.

Upvotes: 2

songyuanyao
songyuanyao

Reputation: 172954

const Ref, given Ref is V&, i.e. float&, note that const is qualified on the reference itself, not the type being referenced. The const qualifier is just omitted, you're still getting V&, but not const V& as you expected. (To be precise there's no const references in C++ but only references to const or to non-const.)

If you change const Ref to const V& (i.e. reference to const), you'll get the error you expected. e.g.

class Inner1: public Util<const V, const V&> {
    ...

Upvotes: 1

Related Questions