Суть в том, что у кого-то это вызвало удивление, а кто то лучше знаком с работой компилятора и понимает смысл ограничений. В твоем случае, для конструирования поинтера необходимо знать точный указываемый тип, потому что указатели на функции имеют разный размер.
Пункт сохранен без изменений в последней редакции драфта, что дает основания предполагать, что если defect reports и были, то отклонены (поиск 14.3.1 по списку дефектов не дал результатов).
J0E Код (Text): template <class T, class F> void check(F T::*) { typedef F F_t; // ill-formed F_t * ptr = &helper; } Почпму ты написал ill-formed возле typedef? Если имеется в виду 14.3.1, то он здесь неприменим - это декларация типа, а не ф-ции.
Это часть первоначального примера. Здесь нет декларации функции. В С++ такого не может быть. > Указатель в принципе не может иметь функциональный тип. Ты с моим утверждением согласен или нет? И в чем ты видишь противоречие? Взяли 'function type', объявили объект, который является указателем на 'function type', сам по себе этот объект имеет 'object type'. Почему и как это происходит - я уже говорил, но ссылки на стандарт ты упорно игнорируешь. В твоем определении такой указатель имеет 'both object and function types'. Это неверно. Ты понимаешь разницу между обявлением указателя на что-то и объявлением функции? В каком? Опять двадцать пять. 'F' не имеет совершенно никакого отношения к 'pointer-to-member' и указатель на такой тип полностью совпадает с типом выражения '&helper'.
Потому что 14.3.1 не говроит о декларации функции в частности, а о любой декларации, в которую вовлечен функциональный тип! =)
Ты понимаешь разницу между объявлением функции (о котором я не веду речь) и объявлением, в которое вовлечен функциональный тип? Ты признал мою трактовку стандарта верной, и споришь с ней =)
Если вы пытаетесь подтвердить свои предположения, компилируя примеры кода, не обольщайтесь, даже comeau нарушает стандарт, ругаясь не на все случаи.
J0E Нет, не говорит. Там рассматривается ситуация (инстанциирование шаблона) приводящая, к тому, что некая декларация, не использующая синтаксис декларации ф-ции, получает тип ф-ции. В приведённом шаблоне нет такой декларации. Есть typedef-декларация типа F_t, к которой данный пункт Стандарта не применим по определению - как можно говорить о типе декларируемой сущности, если эта сущность - тип?
Безусловно понимаю. Только вот эта часть: говорит именно об объявлении функции. Несогласен - приводи ссылки из стандарта. И кроме того, сама схема построения 14.3.1/3 выглядит в виде "If ... and ... the program is ill-formed" требует выполнения двух условий одновременно. Ты видишь только одно. Этот вывод я сделал на основании этого утверждения: Дальше: так как ты не ответил на мой вопрос, то я автоматически буду считать что этой фразой - 'declaration to have both object and function types' ты подтвердил, что не понимаешь разницы между объявлениями функций и объектов. Согласился с переводом. Но ты ее не верно понимаешь. Особенно вот этот момент: "(имеющему функциональный тип)". Несогласен - приведи свое определение для 'function type'. Все мои предположения подкреплены ссылками на стандрат (возможно я что-то и пропустил - скажи где, дам ссылку). Компилируемость как способ доказательства корректности меня сейчас не особо интересует, в частности по тому что "даже comeau нарушает стандарт".
Еще я предлагаю подумать о причинах и смысле ограничения 14.3.1/3. Разруливая противоречия в стандарте, Страуструп говорил: если это выглядит как объявление функции, значит это должно быть объявление функции. 14.3.1/3 говорит об объявлениях, которые не выглядят как объявление функции, но содержат функциональный тип, зависимый от параметра шаблона. Когда компайлер разбирает шаблон, он не может знать наперед тип объявляемого объекта, но ему нужно как-то проверить синтаксис. template<class T>f() { T t; // 0* t = 0; // 1* t(); // 2* } Какое из выражений верно? Если 0* после инстациирования окажется декларацией функции, то ошибку следует выдать на 1*, если t - объект, то ошибку следует выдать на 2*, за исключением случаев, когда t является указателем на функцию (тогда оба варианта могут быть синтаксически корректны, но может быть адресуемая функция ожидает больше параметров?). Что же делать компилятору? Стандарт говорит, что не надо напрягаться. Повдение ВЦ объясняется элементарно: он не проверяет синтаксическую корректность шаблонов до инстанциации. Упрощу 14.3.1/3 Если функциональный тип, зависимый от параметра шаблона, вовлечен в объявление, по синтаксису которого нельзя сказать о функциональности этого типа, программа некорректна. Код Степанова, показывающий правильный вариант, без неоднозначности: template <class Arg, class Result> class pointer_to_unary_function : public unary_function<Arg, Result> { protected: Result (*ptr)(Arg); public: pointer_to_unary_function() {} pointer_to_unary_function(Result (*x)(Arg)) : ptr(x) {} Result operator()(Arg x) const { return ptr(x); } };
Кстати, вот иллюстрация отличия между 'object type' и 'function type': Код (Text): void(*p)(void) = ...; sizeof(*p); // error Результатом выражения '*p' является lvalue типа 'void()', но согласно 5.3.3/1/3 оператор 'sizeof' неприменим к 'function types'. А вот 'sizeof(p)' совершенно легальная конструкция, т.к. применяется к lvalue типа 'void(*)(void)', т.е. к указателю на <функцию>. И здесь совершенно не важен 'указуемый' тип.
Словами стандарта: A name declared with the typedef specifier becomes a typedef-name. ... A typedef-name is thus a synonym for another type.
Причем здесь Страуструп. Способ разрешения неоднозначностей, о которых ты говоришь описан в ISO/IEC 14882 в параграфе 6.8 и 8.2, которые так и называются: "Ambiguity resolution". В 6.8 описан способ разрешения неоднозначностей между 'expression-statements' и 'declarations', в 8.2 описываются способы разрешения неоднозначностей между 'function-style cast' и declaration в контексте 'declaration statements' и некоторых других неоднозначностей. Связи с 14.3.1/3 я не вижу. Это упрощение никуда не годится (разве что букв меньше) - взял выкинул одно из условий.
J0E То, что ты пытаешься к этому объявлению применить 14.3.1. Повторюсь - там рассматривается ситуация (инстанциирование шаблона), приводящая (cause) к тому, что некая декларация, не использующая синтаксис декларации ф-ции (that does not use the syntactic form of a function declarator), получает тип ф-ции (to have function type). typedef-декларация под это описание не подходит в принципе - typedef-name is type, а не has type.
Тип - это множество объектов с общим набором свойств. "Объект имеет тип Т" означает, что объект является элементом множества, определяемого типом T. Пример. Число 1 есть элемент множества натуральных чисел N. Т.е. можно говорить что 1 имеет тип N. Но само множество N не является элементом N(т.е. себя самого). Т.е. нельзя сказать, что N имеет тип N.
Объявление function type (nop, ты просил - см до просветления синтаксис в 8.3.5/1) void(*)(const int); // выражение has type "void(*)(const int)" typedef void(*pfn_t)(const int); // pfn_t has type "void(*)(const int)". OR the type of pfn_t is "void(*)(const int)" По русски можно сказать: тип выражений "void(*)(const int)". Оба эти выражения декларируют функциональный тип "void(int)". Помимо этого, они декларируют указатель на этот тип. Помимо этого, они декларируют, что параметр функции, на которую указывает поинтер, имеет тип int. Синтаксис языка определяет simple-declaration: decl-specifier-seq.opt init-declarator-listopt ; decl-specifier-seq: decl-specifier-seq.opt decl-specifier Это разбирается рекурсивно, подобно compound type (что игнорируется Пустым Опкодом). Семантическа одинакова, можно declaration-seq разделить на несколько simple-declaration, то есть разделить декларации ; как я пытался показать примером с typedef. Поэтому буквально переводите declaration has type - в декларации присутствует тип. Функциональный тип является неотъемлемой частью типа указателя на функцию, что необходимо для их различения от указателей на объекты (в том числе и произвольный объект - void*. как насчет произвольной функции?. 14.3.1/3 (не теряйте, без параграфа смысл другой - видно что стандарт не читаете) стандарта запрещает декларацию функционального типа с использованием зависимого от параметров шаблона типа, но без использования синтаксиса "()". Независимо от того, в каком месте появляется эта декларация, в том числе и как подвыражение в другой декларации, программа инвалидна. Обратите особое внимание, что я нигде не говорю о декларации функции! Что бы декларировать функциональный тип, не обязательно объявлять функцию, поэтому 7/5 (the declaration is called a function declaration if the type associated with the name is a function type and an object declaration otherwise) не имеет значения. Под ассоциированным типом понимается тип, который при разборе будет выведен первым - то есть указатель. Это должно быть настолько очевидно, что стандарт не дает четкого отдельного определения function type, однако упоминает в нужном мне контексте: [ Note: Function types (including those used in pointer to member function types) are never cv-qualified (8.3.5). —end note ] и 8.3.5/4 A cv-qualifier-seq shall only be part of the function type for a nonstatic member function, the function type to which a pointer to member refers, or the top-level function type of a function typedef declaration. The effect of a cv-qualifier-seq in a function declarator is not the same as adding cv-qualification on top of the function type, i.e., it does not create a cv-qualified function type. и далее в этом пункте даже объясняется, почему при объявлении объекта-указателя с инициализацией имеет значение функциональный тип: [Note: function types are checked during the assignments and initializations of pointer-to-functions, reference-to-functions, and pointer-to-member-functions. ] Первая попавшаяся ссылка для любителей точность в английском Use typedef to define a function type for function pointer Мне совершенно понятно упорство, с которым Пустой Опкод защищает свою точку зрения, он когда-то вырезал ножиком целый отряд в контр-страйк. Я знаю это, как и многое другое, что не показываю раньше времени. На первых страницах я закинул жирную наживку Мне было интересно, что кроется за словами "читай стандарт" на этом форуме (до этого оказывалось, что люди бросаются такими словами почем зря). На самом деле, мне было бы гораздо интереснее, если бы показали, что я не прав. Боюсь, что для этого следует форвардить вопрос на какой то более компетентный ресурс, например RSDN? Здесь нет кворума. P.S. Я достаточно читал стандарт, что бы прийти к выводу, что знаю его плохо, и понять, что человек, утверждающий, что знает его хорошо - понимает может 5%. По сути, досконально стандарт не понимает никто, иначе не находилось бы такого количества defect reports.
Не фантазируй, никакого множества объектов в языке С++ нет. Бывают 2 вида типов: fundamental (определенные языком) и compound (состоящие из фундаментальных). Типы характеризуют объекты, ссылки, или функции. struct s : s1, s2 {} // s IS-A s1 AND s IS-A s2 struct s { s1 s1_; s2 s2_ }; // s HAS-A s1 AND s HAS-A s2. ISA и HASA - устоявшиеся идиомы
Это не выражение, это type-id. Синтаксис выражений определяется в 5.1 и конструкцию 'void(*)(const int)' ты при всем желании не разберешь как expression. 'Декларируют' не типы, а имена: Заметь, слово 'declaration' в стандарте в этом месте выделено курсивом - это значит что именно эта фраза является определением для 'declaration'. Т.е. обявляются имена, поэтому, например, можно говорить о 'namespace declaration' и т.д. Неверно. Во-первых само по себе 'выражение' (как expression) не может ничего 'декларировать'. В некоторых случаях декларация имен в выражениях допустима, но все о чем ты говоришь к этому не относится. Во-вторых: вот здесь - "void(int)" нет никакого имени, поэтому и о декларации говорить не приходится. Только во втором случае ('pfn_t') Твое первое "выражение" не декларирует ничего (согласен?). Про параметры пока можно пропустить, чтобы не усложнять (они здесь малозначимы). Неверно. 'simple-declaration' не рекурсивно относительно себя. Вот здесь: void (*p)(int) = 0; declaration-seq представляет из себя (сюрприз!) - 'void', а 'init-declarator-list' - '(*p)(int) = 0'. Т.к. init-declarator-list может представлять из себя список из 'init-declarator'ов, то можно например писать так: void (*p)(int) = 0, (*p2)() = 0; Неверно. Даже сама постановка фразы 'в декларации присутствует' неверна. Имя, введенное определением, может обозначать 'value, object, subobject, base class subobject, array element, variable, function, instance of a function, enumerator, type, class member, template, or namespace' (3/3). Теперь очевидно, что фраза 'в декларации присутствует тип' в общем случае не имеет смысла? При обявлении объекта-указателя тот получает тип: 'указатель на T' (3.9.2/3, 8.3.1/1). Для pointer-to-memeber применяется несколько другая формулировка: 'pointer to member of class X of type T' (8.3.3/1). Само объявление при этом называется 'object-declaration' (7/5): С этим согласен? Неверно. Несогласен - приводи конкретные синтаксические констукции, приводящие к декларации имени, которое имеет 'function type' и отлично от декларации функции (за исключением 8.3.5/7). Ты же не будешь бросаться голословными утверждениями? Сказал как отрезал. Неверно, см. вопрос выше. Уже горячо. ... а если это указатель, то объявляение называется 'object declaration' (7/5). Согласен. Неверно: 1.3/2 А 8.3.5/1 в свою очередь заканчивается так: [Заменил italic на bold, в цитатх везде italic] Абсолютно четкое определение (учитывая то что скрывается за многоточием). Чуть выше находится условие, которое должно выполнится для того чтобы мог появиться 'function type'. Задача: попытаться проверить это условие применительно к первоначальному примеру. В ненормативном 'Note'? Задача: найти хоть один cv-qualifier в исходном примере. Опять ты ссылаешся на ненормативный текст. Вот правильная ссылка - ISO/IEC 14882. Ты обознался. Переход на личности detected. Повторишься - мне придется закончить эту дисскуссию, поскольку смысл обсуждения для тебя переходит в другую колею. Внимательно прочитай то что я тебе написал и постарайся ответить на вопросы. Согласен/несогласен/и.т.п Пока ты бездумно выдираешь фразы из стандарта и пытаешся их как-то 'прикрутить' к обсуждаемому вопросу и игнорируешь любые конструктивные ответы - никакого конструктивного диалога не получится.