C++: почему новое размещение оператора не распознается как встроенная функция друга в классе (шаблоне) в VS2005?

Я унаследовал проект Visual Studio 6.0 для преобразования в 2005. Он включает в себя этот фантастический класс MyClass ниже, который клиентский код использует везде, вызывая новое размещение в его экземпляре (здесь это значительно упрощено):

#include <new>
#include <cstdio>

template<class T>
class MyClass {
public:

    // This is what the author assumed would be called on placement new.
    inline friend void* operator new(size_t u_size, MyClass<T>& mc) {
        printf("MyClass friend placement new\n");
        // ...
        return 0;
    }

    // This is just to show koenig lookup works on normal functions.
    inline friend void hello(MyClass<T>& mc) {
        printf("Hello called with koenig lookup\n");
        // ...
    }

    // This was part of the original class, gets called further below.
    operator unsigned int*() {
        printf("Converting for default placement new\n");
        // ...
        return 0;
    }
};

/* This gets called in VS2005 if un-commented.
template<class T>
void* operator new(size_t u_size, MyClass<T>& mc) {
    printf("MyClass placement new non-friend non-inline\n");
    // ***
    return 0;
}
*/

class DummyClass {    
   int a;
};

void testfunction() {
    MyClass<DummyClass> mc;
    hello(mc);
    void* a = new(mc) DummyClass; // Placement new call

    char c;
    gets(&c);
}

Когда я запускаю "testfunction()" в VS2005, при вызове нового размещения оператор "inline friend void* operator new(...)" в MyClass никогда не вызывается. Вместо этого вызывается «operator unsigned int*()», результат приводится к void*, и вместо этого вызывается оператор размещения по умолчанию new (поэтому отображается «Преобразование для размещения по умолчанию new»).

В VS6 новое размещение вызывает «встроенный друг void* operator new(...)» в MyClass вместо этого (поэтому отображается «новое размещение друга CMyClass»), что и предполагалось автором, но затем снова VS6 реализует встроенных друзей в странный способ.

Почему VS2005 не распознает встроенный оператор размещения друзей new с использованием поиска, зависящего от аргумента? Он распознает функцию hello() с использованием аргументов (поэтому отображается сообщение «Hello, вызванное поиском koenig»), но не работает для размещения new.

Для справки: кажется, что это происходит независимо от того, является ли MyClass шаблонным или нет (но я оставил его шаблонным для полноты картины). Кроме того, если вы раскомментируете недружественный «новый оператор» за пределами MyClass, он будет правильно вызван в VS2005.

Что дает? Там ошибка? Является ли размещение new особым случаем поиска, зависящего от аргумента? VS2005 прав или нет? Что было бы здесь стандартным С++?

В качестве обходного пути я собирался использовать не встроенного друга вместо встроенного, но это становится уродливым с форвардами и всем остальным, я хотел сначала спросить, в чем здесь дело.


person DustOff    schedule 06.03.2010    source источник
comment
Действительно странно. То же самое работает с Comeau Online, но GCC находит перегруженный новый оператор. - Тем не менее, шаблоны в любом случае неявно встроены. Кажется, это работает, если вы определяете оператор вне класса.   -  person UncleBens    schedule 06.03.2010
comment
ADL работает только с вызовами функций с именами, не заключенными в круглые скобки, и где используется явная ссылка на этот ADL (например, a + b by 13.3.1.2/3). Как процитировал @avakar, new не такой случай.   -  person Johannes Schaub - litb    schedule 07.03.2010


Ответы (1)


Проблема в том, что функция распределения ищется в глобальной области видимости, а не с помощью ADL. Поскольку дружественные функции, определенные внутри класса, скрыты от окружающей его области, функция не найдена.

5.3.4/9:

Если новое выражение начинается с унарного оператора ::, имя функции распределения ищется в глобальной области видимости. В противном случае, если выделенный тип является типом класса T или его массивом, имя функции выделения ищется в области T. Если этот поиск не находит имя или если выделенный тип не является типом класса, выделение имя функции просматривается в глобальной области видимости.

person avakar    schedule 06.03.2010
comment
Ок, спасибо, достаточно просто. Так что это была еще одна жертва распущенности VC6. - person DustOff; 07.03.2010