Доброго дня.
Вот есть такой код:
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
Есть какие-то мысли?
Спасибо.