9/24/2004

  Интересный способ перегрузки оператора "запятая" - (C++) 10:19 am

Взято с RSDN, вот отсюда

template<class T_numtype, class T_iterator>
class ListInitializer
{
public:
    ListInitializer(T_iterator iter) : iter_(iter) { }
    ListInitializer<T_NUMTYPE, T_iterator> operator,(T_numtype x)
    {
        *iter_ = x;
        return ListInitializer<T_NUMTYPE,T_ITERATOR>(iter_ + 1);
    }
private:
    ListInitializer();
protected:
    T_iterator iter_;
};
class Array
{
public:
    Array(std::size_t size = 10) : data_(new double[size])
    {
    }
    ~Array()
    {
        delete [] data_;
    }
    ListInitializer<DOUBLE,DOUBLE*> operator=(double x)
    {
        data_[0] = x;
        return ListInitializer<DOUBLE,DOUBLE*>(data_ + 1);
    }
private:
    double* data_;
};
int main()
{
    Array A(5);
    A = 0.1, 0.2, 0.3, 0.4, 0.5; // comma initialization list
}

Также из этой темы узнал, что оператор запятая - единственная “функция", которая может синтаксически принимать аргумент типа void.

3.9.1 9

The void type has an empty set of values. The void type is an incomplete type that cannot be completed.It is used as the return type for functions that do not return a value. Any expression can be explicitly converted to type cv void (5.4). An expression of type void shall be used only as an expression statement (6.2), as an operand of a comma expression (5.18), as a second or third operand of ?: (5.16), as the operand of typeid, or as the expression in a return statement (6.6.3) for a function with the return type void.

Также в этой теме описаны способы определения существования перегруженной функции с определенным параметром.

struct no_suitable_overload {};
no_suitable_overload my_func(…);
typedef char yes;
typedef char(&no)[2];
// Похоже оператор запятая - единственная “функция", которая может синтаксически принимать аргумент типа void
// и при этом может быть перегружена. Этим и воспользуемся.

no operator,(no_suitable_overload, yes);
// T2 operator,(T1, T2); // “обычная перегрузка” запятой, в нашем случае T2 == yes, а T1 может быть void
template<class T>
struct has_my_func
{
enum { value = sizeof((my_func((T*)0), yes())) == sizeof(yes) };
};

С ценными замечаниями об особенностях работы компилятора при поиске перегруженных функции и инициализации фаблонов.

Но есть еще другое. Для comeau имеет значение, объявлена перегрузка до или после определения шаблона:
struct no_suitable_overload {};
no_suitable_overload my_func(…);
typedef char yes;
typedef char(&no)[2];
no operator,(no_suitable_overload, yes);

void my_func(int*); // эту перегрузку comeau находит

template<class T>
struct has_my_func
{
    enum { value = sizeof(my_func((T*)0), yes()) == sizeof(yes) };
};

void my_func(short*); // а эту не находит

char a[has_my_func<int>::value];
char b[has_my_func<short>::value]; // ошибка

А VC7.1 находит обе перегрузки. Похоже что my_func в шаблоне является независимым именем и их вызовы должны связываться при первичном разборе шаблона. У VC есть специальный баг на этот счет: http://msdn.microsoft.com/library/en-us/vclang/html/vclrf1462dependentnames.asp.

Гуру, это так? Как можно считать my_func независимым именем, если выбор перегрузки зависит от параметра шаблона?

Нельзя.

Компилятор должен осуществлять two-phace lookup для неквалифицированных зависимых имен. Первая фаза осуществляется в точке определения шаблона, вторая в точке инстанцированния. На второй фазе осуществляется только ADL. Набор ассоциированных с short имен пустой, поэтому компилятор не должен найти void my_func(short*), что Comeau и делает.

Но, two-phase lookup осуществляют только EDG-based compilers, MetroWerks, и будущий gcc 3.4. Microsoft обещает добавить в следующей версии. Те компиляторы, которые не делают two-phase lookup, связывают имена в точке инстанциирования, поэтому MS находит обе перегрузки.

Что не приятно, это то, что переход с компилятора не поддерживающего two-phase lookup, на компилятор с оным, в случае как этот, может в лучшем случае поломать в код, а в худшем тихонько скомпилироваться, использовав другую версию ф-ции для аргумента встроенного типа.

Комментарии

Нет комментариев.

Оставить комментарий

Комментарии к этой записи закрыты.