Вот блин, сходил за спичками... делал простенький синглетончик...
Комяу не нашёл проблем — а шестёрка нашла.
#include <iostream>
using namespace std;
template<class T>
struct Common
{
int i;
static Common self;
};
template<class T>
Common<T> Common<T>::self = { 0 };
template<class T>
Common<T>& common(const volatile T* v)
{
return Common<T>::self;
}
class Test
{
public:
void f() const
{
Common<Test> dummy = { 1 };
dummy = common(this); // error!
dummy = Common<Test>::self; // ok
cout << common(this).i << endl;
}
void g()
{
common(this).i = 1;
}
};
int main()
{
Test t;
t.g();
t.f();
}
Результат VC6 заявил
e.cpp(27) : error C2679: binary '=' : no operator defined which takes a right-hand operand
of type 'struct Common<class Test>' (or there is no acceptable conversion)
Если мы уберём проблемную строку, и просто будем пользоваться common(this) и Common<Test>::self -- обнаружим, что у них разные адреса!
Оказывается, это попросту разные типы:
class Test
{
public:
void f() const
{
cout << typeid(&common(this)).name() << endl; // struct Common<class Test const > *
cout << typeid(&Common<Test>::self).name() << endl; // struct Common<class Test > *
// |
// +---- чтобы избавиться от ссылочного типа
}
};
main()
{
Test test;
const Test ctst;
test.f();
cout << typeid(&common(&test)).name() << endl; // struct Common<class Test > *
cout << typeid(&common(&ctst)).name() << endl; // struct Common<class Test const > *
}
Засада притаилась вот где:
template<class T>
Common<T>& common(const volatile T* v)
стоит нам убрать volatile — и всё встаёт на место.
Оба квалификатора добавлены с единственной целью: не различать указатели на класс с и без этих квалификаторов.
То есть
Test t;
Test* p = &t;
const Test* pc = &t;
volatile Test* pv = &t;
const volatile Test* pvc = &t;
После такой находки я бы поостерёгся пользоваться
библиотекой Loki, где этих volatile — как собак нерезанных, именно с целью ингибирования cv-квалификаторов.
ЗЫ.
Проверьте на VC7, плиз.