Re[5]: Ограницения template type arguments
От: Юрий Жмеренецкий ICQ 380412032
Дата: 02.02.10 20:45
Оценка: 6 (1)
Здравствуйте, Anonim547, Вы писали:

A>Здравствуйте, Юрий Жмеренецкий, Вы писали:


ЮЖ>>Единственный вид объявления (не учитывая 8.3.5/7), порождающее имя, которое имеет 'function type' — это 'function declaration' (декларация объектов-функций запрещена), 'typedef-declaration' создает только синоним для существующего типа.


A>Если 'function type' не зависит от параметов шаблона, декларация функций не запрещена. Выглядит логичным, что проблема не в декларации функции, как таковой, а в зависимости типа от параметров шаблона.


A>Отсюда возникает вопрос: какова причина запрета на такой тип, нет ли в 14.3.1/3 неточностей, и не следует ли распространять причины запрета на другие случаи?


Имхо, причина там одна — не дать возможность объявления объекта, который имеет 'function type'. В качестве альтернативы можно рассмотреть случай когда такая конструкция приводит к декларации функции, как и в случае c 8.3.5/7. Но это может привести к сюрпризам, т.к. инстанцирование шаблона функциональным типом и любым другим будет приводить к совершенно разным последствиям. Т.е. здесь как мне кажется имеет место "принцип наименьшего удивления": конструкция вида 'T f;' предствляет собой 'object declaration' и только ее, а попытка использования в качестве 'T' функционального типа приводит к ошибке. В случае же с независимыми типами, декларация функции в этом случае — осмысленный шаг со стороны программиста (и результат ни от чего не зависит).

Хотя вот еще интересный момент:

typedef void X();
void g(X)

template<class F>
struct A
{
  void f(F f);
};


В случае с 'g' ее фактический тип будет 'void(void(*)())' согласно 8.3.5/3. В случае c А<void()>::f логично было бы ожидать такого же поведения, но 14.3.1/3 вводит запрет на более ранней стадии:

8.3.5/3
The type of a function is determined using the following rules. The type of each parameter is determined from its own decl-specifier-seq and declarator. After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively.

14.3.1/3
If a declaration acquires a function type through a type dependent on a template-parameter and this causes a declaration that does not use the syntactic form of a function declarator to have function type, the program is ill-formed.


A>Поясню на примере, вопрос возник при анализе следующего:

A>
A>void helper()
A>{
A>}

A>struct foo
A>{
A>    void bar() {}
A>};

A>template <class T, class F>
A>void check(F T::*)
A>{
A>    F* ptr = &helper; // error C2440: 'initializing' : cannot convert from 'void (__cdecl *)(void)' to 'void (*)(void)'
A>}

A>int main()
A>{
A>    check(&foo::bar);
A>    return 0;
A>}
A>

A>Компайлер рассматривает calling convention как часть сигнатуры, стандартом это не определено, но как быть? В зависимости от установленной по умолчанию calling convention, VC выдает C2440 или ICE.

Тип для 'F' будет выведен как 'void()', соответственно тип 'ptr' будет 'void(*)()', что соответствует типу выражения '&helper'. Т.е. никаких проблем быть не должно. А здесь точно именно этого требуется?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.