template<class T> struct A {
static T t; // 1
T *pt; // 2
};
typedef int function();
A<function> a; // ill-formed: would declare A<function>::t
// as a static member function
Comeau ругает строку с // 1
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.
Проясните ситуацию в случае 2, должен ли компайлер разрешать, или нет? какие причины запрета в 1?
Здравствуйте, Аноним, Вы писали:
А>Большинство компайлеров транслируют:
... до тех пор, пока ты не обратишься к соответствующему члену.
А>Comeau ругает строку с // 1
Ибо, как можно сделать переменную типа "функция"?
Вот переменную типа "указатель на функцию" — запросто.
Здравствуйте, Кодт, Вы писали:
К>Ибо, как можно сделать переменную типа "функция"? К>Вот переменную типа "указатель на функцию" — запросто.
Насколько я успел понять, вопрос в трактовке 14.3.1/3. Стандарт не запрещает использовать тип таким образом:
typedef int function();
template<class T> struct A {
// static T t; // 1 - ill-formed, type dependent on a template-parameterstatic function t; // 1a - Ok
T *pt; // 2 - ???typedef T T2; // 3 - ???
};
A<function> a; // комментарии выше указаны исключительно для данной специализации
Здравствуйте, Аноним, Вы писали:
А>Большинство компайлеров транслируют: А>
А>template<class T> struct A {
А>static T t; // 1
А>T *pt; // 2
А>};
А>typedef int function();
А>A<function> a; // ill-formed: would declare A<function>::t
А> // as a static member function
А>
А>Comeau ругает строку с // 1 А>
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.
А>Проясните ситуацию в случае 2, должен ли компайлер разрешать, или нет?
Также разрешено — вторая часть 14.3.1/3 не выполнится:
... and this causes a declaration ... to have function type
Единственный вид объявления (не учитывая 8.3.5/7), порождающее имя, которое имеет 'function type' — это 'function declaration' (декларация объектов-функций запрещена), 'typedef-declaration' создает только синоним для существующего типа.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Единственный вид объявления (не учитывая 8.3.5/7), порождающее имя, которое имеет 'function type' — это 'function declaration' (декларация объектов-функций запрещена), 'typedef-declaration' создает только синоним для существующего типа.
Если 'function type' не зависит от параметов шаблона, декларация функций не запрещена. Выглядит логичным, что проблема не в декларации функции, как таковой, а в зависимости типа от параметров шаблона.
Отсюда возникает вопрос: какова причина запрета на такой тип, нет ли в 14.3.1/3 неточностей, и не следует ли распространять причины запрета на другие случаи?
Поясню на примере, вопрос возник при анализе следующего:
Компайлер рассматривает calling convention как часть сигнатуры, стандартом это не определено, но как быть? В зависимости от установленной по умолчанию calling convention, VC выдает C2440 или ICE.
Здравствуйте, 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' функционального типа приводит к ошибке. В случае же с независимыми типами, декларация функции в этом случае — осмысленный шаг со стороны программиста (и результат ни от чего не зависит).
В случае с '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'. Т.е. никаких проблем быть не должно. А здесь точно именно этого требуется?
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ> Но это может привести к сюрпризам, т.к. инстанцирование шаблона функциональным типом и любым другим будет приводить к совершенно разным последствиям.
Здравствуйте, Юрий Жмеренецкий, Вы писали:
ЮЖ>Имхо, причина там одна — не дать возможность объявления объекта, который имеет 'function type'. В качестве альтернативы можно рассмотреть случай когда такая конструкция приводит к декларации функции, как и в случае c 8.3.5/7. Но это может привести к сюрпризам, т.к. инстанцирование шаблона функциональным типом и любым другим будет приводить к совершенно разным последствиям. Т.е. здесь как мне кажется имеет место "принцип наименьшего удивления": конструкция вида 'T f;' предствляет собой 'object declaration' и только ее, а попытка использования в качестве 'T' функционального типа приводит к ошибке.
Спасибо.
ЮЖ>В случае же с независимыми типами, декларация функции в этом случае — осмысленный шаг со стороны программиста (и результат ни от чего не зависит).
Руководствуясь тем, что IS нацелен больше на разработчиков транслторов, чем на рядовых программистов, префразирую:
Независимый тип известен при определении шаблона и используется в проверке синтаксиса. Зависимый тип станет известен позже при инстанциации.
Что бы исключить какие-то сложности/неоднозначности при определении шаблона, стандарт делает запрет явно. VC не особо проверяет синтаксис внутри шаблона до инстанциации, поэтому успешно транслирует ill-formed example из 14.3.1/3.
ЮЖ>Тип для 'F' будет выведен как 'void()', соответственно тип 'ptr' будет 'void(*)()', что соответствует типу выражения '&helper'. Т.е. никаких проблем быть не должно.
Ситуация не стандартна из-за разных конвенциий вызова.
ЮЖ>А здесь точно именно этого требуется?
К сожалению, автор кода не дал ответа на этот вопрос. Что-то связанное с выводом сигнатуры функций.
Мне кажется, каждый встречающийся в объявлении функции тип выводят по отдедьности, стремясь к:
RT f(A);
что не может попасть под ограничение. Как следствие усомнился, что формулировка стандарта безупречна, как минимум для моего понимания.
Здравствуйте, Аноним, Вы писали:
А>Большинство компайлеров транслируют: А>
А>template<class T> struct A {
А>static T t; // 1
А>T *pt; // 2
А>};
А>typedef int function();
А>A<function> a; // ill-formed: would declare A<function>::t
А> // as a static member function
А>
А>Comeau ругает строку с // 1 А>
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.
А>Проясните ситуацию в случае 2, должен ли компайлер разрешать, или нет? какие причины запрета в 1?
Как раз на днях активно исследовал тему функционального типа, так как еще месяц назад о таком не подозревал.
Дьюхарст пишет по этому поводу, что при помощи typedef'а можно объявлять только нестатические методы класса. Однако в MVS 2008 и в MVS 6.0 прекрасно компилируются и статические методы классов и глобальные функции определенные через typedef.
Описание таких определений приводится в
8.3.5/7 A typedef of function type may be used to declare a function but shall not be used to define a function (dcl.fct.def). [Example:
typedef void F();
F fv; // OK: equivalent to void fv();
F fv { } // ill-formed
void fv() { } // OK: definition of fv
--- end example] A typedef of a function type whose declarator includes a cv-qualifier-seq shall be used only to declare the function type for a nonstatic member function, to declare the function type to which a pointer to member refers, or to declare the top-level function type of another function typedef declaration. [Example:
typedef int FIC(int) const;
FIC f; // ill-formed: does not declare a member function
struct S {
FIC f; // OK
};
FIC S::*pm = &S::f; // OK
--- end example]
Однако 14.3.1/3 похоже запрещает такую же конструкцию для шаблонов. Печально, я только придумал как это можно красиво использовать...