Nested template classes, private access
От: wander  
Дата: 12.01.17 10:31
Оценка:
Доброго дня.

Вот есть такой код:
class Holder
{
public:
    template <size_t I>
    class ConstRef;
        
    template <size_t I, class C = Holder>
    class Ref;
        
    template <size_t I, class C>
    class Ref
    {
        friend class Holder;

        Ref(C & ref)
            : m_ref(ref)
        { }

    public:
        Ref(Ref<I> const & x) // [2] этот конструктор задействован в [1]
            : m_ref(x.m_ref)  // WTF?
        { }
       
    private:
        C & m_ref;
    };

    template <size_t I>
    class ConstRef
        : public Ref<I, Holder const>
    {
        friend class Holder;
            
        ConstRef(Holder const & ref)
            : Ref<I, Holder const>(ref)
        { }
            
    public:
        ConstRef(Ref<I> const & ref) // [1] преобразование Ref в ConstRef
            : Ref<I, Holder const>(ref)
        { }        
    };
    
    template <size_t I>
    ConstRef<I> makeRef() const
    {
        return *this;
    }
    template <size_t I>
    Ref<I> makeRef()
    {
        return *this;
    }
};

int main()
{
    Holder holder;
    
    Holder::Ref<0> ref = holder.makeRef<0>();
   
    Holder::ConstRef<0> ref0(ref); // [0] -> [1]
}

И что-то у меня большие сомнения, что он должен работать.
В точке [2] у нас написан конструктор копирования. В случае, когда Ref<I> одинаковый справа и слева, все правильно (параметр С по умолчанию совпадает) — классы одинаковые. А вот в точке [1] у нас получается, что классы разные, т.к. разный параметр С: С const у приемника и C у источника. Конструктор имеет вид
Holder::Ref<I, Holder const>::Ref(Ref<I, Holder> const & x)

Разве не должен компилятор мне здесь дать по рукам, сказать что m_ref в private и отказаться компилировать?
Тем не менее, этот пример работает во всех компиляторах, в которых я смог его проверить (intel, cl, gcc, clang).

Вот, пожалуйста, тест в cl: http://rextester.com/LOIREM91370
Или в clang: http://rextester.com/UBL12366

Есть какие-то мысли?
Спасибо.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.