В компайл-тайм все объекты константные. Будь то интегральные значения или типы. Т.е. имея запись:
const int i = some::val;
typedef some::type type;
всегда some::val будет иметь одно и то же значение и some::type будет одним и тем же типом. В принципе можно к этому добавить входные агрументы:
const int i = some<char, 5>::val;
typedef some<int, 15>::type type;
но результат всё равно всегда однозначно определяется входными значениями. Т.е. это фактически функциональный язык с константными объектами.
Так вот, всё это неправда!
Сейчас вы увидите, как на стандартном с++ можно иметь переменные значения в компайл-тайм!
char engine(...);
template<typename, int> struct magic;
typedef magic<char, -1> magicc;
template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
struct magic
{
friend int engine(magicc&, type&);
static const int val = id;
};
int main()
{
char a[magic<>::val != magic<>::val ? 1 : -1];
}
Код копилируется gcc4.1/msvc7.1/msvc8.0/edg c++
Вы скажете "Ну и что? Что с помощью этого можно сделать?"
Всё, что можно сделать, я пока не знаю, но знаю, что сделать можно много. Собственно для этого, в частности, я это и публикую, что бы общественность могла придумывать свои применения.
Вот какие применения я на данный момент придумал:
1. Компайл-тайм счётчик. Аналог __COUNTER__, тока лучше. Фичи:
— в любом месте можно завести свой "личный" экземпляр счётчика, т.е. он будет всегда начинать считать с нуля, а не с произвольного меняющегося числа.
— можно генерировать не только последовательность натуральных чисел, а произвольные последовательности: степени 2 (1, 2, 4, 8 ...), чётные числа (0, 2, 4, 6 ...), в сторону уменьшения (0, -1, -2, -3 ...) и т.д.
— если счётчик используется внутри шаблона, будет генерироваться новое значение для каждой специализации шаблона
— можно получить текущее значение счётчика, не инкрементируя его
— типизированный счётчик — выдаёт, например, значения типа short
Примеры использования:
// Просто получаем значение счётчикаint i = cnt<>::val;
// Заводим "личный" счётчикstruct my_tag;
int j = cnt<my_tag>::val;
// Генерируем последовательность степеней двойкиstruct my_tag2;
enum x
{
val1 = cnt<my_tag2, pow2gen>::val,
val2 = cnt<my_tag2, pow2gen>::val,
val3 = cnt<my_tag2, pow2gen>::val
};
2. Компайл-тайм генератор случайных чисел.
Никаких особых фич и распределений я не делал. Пример использования:
// Создали массив из 3 случайных чисел от 5 до 20 int data[] = {rnd<5, 20>::val, rnd<5, 20>::val, rnd<5, 20>::val};
3. ... не знаю как назвать... легче на примере показать. Допустим есть класс:
Как это работает? Заводится приватный счётчик (cnt<person>). Каждый член получает текущее значение этого счётчика — это есть его смещение. Далее инкрементирует счётчик на свой размер. И уаля. В реальности ещё приходится делать поправку на выравнивание, но это уже детали.
Это даёт возможность членам обращаться к своему контейнеру и наоборот.
Добавляем к этому регистрацию типов (здесь
) и получаем не больше и не меньше, а compile-time reflection!!!
Для такого класса мы знаем порядок, типы и смещения членов — реализация, например, бинарной сериализации далее видится тривиальной
Здравствуйте, remark, Вы писали:
R>Сейчас вы увидите, как на стандартном с++ можно иметь переменные значения в компайл-тайм!
R>
R>char engine(...);
R>template<typename, int> struct magic;
R>typedef magic<char, -1> magicc;
R>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>struct magic
R>{
R> friend int engine(magicc&, type&);
R> static const int val = id;
R>};
R>int main()
R>{
R> char a[magic<>::val != magic<>::val ? 1 : -1];
R>}
R>
Хм... Оригинально, но не понятно, должно ли это работать так, как задумано. Как известно, friend declaration не вводит в охватывающий namespace видимого имени. Поэтому не ясно, почему в твоем случае при второй инстанциации 'magic' lookup для дефолтного аргумента вдруг должно найти именно "друга", а не явно объявленную оригинальную версию 'engine'...
На Comeau Online — не работает. А именно, оба 'magic<>::val' одинаковы.
Best regards,
Андрей Тарасевич
Re: Невероятно, но факт! Не константные значения в компайл-т
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Хм... Оригинально, но не понятно, должно ли это работать так, как задумано. Как известно, friend declaration не вводит в охватывающий namespace видимого имени. Поэтому не ясно, почему в твоем случае при второй инстанциации 'magic' lookup для дефолтного аргумента вдруг должно найти именно "друга", а не явно объявленную оригинальную версию 'engine'...
Да, friend declaration не вводит в охватывающий namespace видимого имени. Всё правильно. Над этой проблемой пришлось побороться.
На помощь пришёл ADL! Смотри:
Это же работает, хотя тоже вроде как не должно, т.к. operator + () вообще говоря не виден вне класса.
Поэтому я добавил в функцию engine() параметр magic&! Теперь она тоже попадает в рассмотрение!
АТ>На Comeau Online — не работает. А именно, оба 'magic<>::val' одинаковы.
Здравствуйте, Roman Odaisky, Вы писали:
RO>Здравствуйте, remark, Вы писали:
R>>Пришло время очередного ресёрча
RO>Я попробовал на VC9, только первые 2 значения разные
Во-первых, это уже круто!
Во-вторых, что такое VC9
В-третих, Да, всё правильно, тут я только для двух сделал, что бы было хоть чуть-чуть понятно как работает
Здравствуйте, IROV.., Вы писали:
IRO>Будь проще и люди подтянутся
А зачем они мне?
IRO>А то что только первое и второе вхождение будет, видно из кода, точнее из за механизма!
Да, тут я привёл только для двух, что бы было понятнее. Смотри здесь
для полной версии счётчика.
IRO>Вся ботва в двух ключевых моментах а именно
IRO>char engine( ... ); // выбор данной функции при перегрузке всегда последния (скока можно красивых вещей на этом сделать)
Не понял, что имеется в виду...
Да, engine(...), имеет наименьший приоритет при выборе перегрузок, на этом всё и построено...
IRO>и то что sizeof() не ищет реализацию а только оглавление.
Опять не понял...
IRO>Комеаут скорее всего не работает так как надо, потомучто он не успел найти обявление friend int engine(_true);
Да, Комеаут не работает, я знаю, но это не ко мне, а к нему
Здравствуйте, remark, Вы писали:
R>Здравствуйте, IROV.., Вы писали:
IRO>>Будь проще и люди подтянутся R>А зачем они мне?
А в прочем ты прав _люди_ такое не используют
IRO>>А то что только первое и второе вхождение будет, видно из кода, точнее из за механизма!
R>Да, тут я привёл только для двух, что бы было понятнее. Смотри здесь
Здравствуйте, IROV.., Вы писали:
IRO>Здравствуйте, remark, Вы писали:
R>>Здравствуйте, IROV.., Вы писали:
IRO>>>Будь проще и люди подтянутся R>>А зачем они мне? IRO>А в прочем ты прав _люди_ такое не используют
Я никого не принуждаю это использовать, и даже читать не принуждаю...
IRO>>>А то что только первое и второе вхождение будет, видно из кода, точнее из за механизма!
R>>Да, тут я привёл только для двух, что бы было понятнее. Смотри здесь
Здравствуйте, remark, Вы писали:
R>3. ... не знаю как назвать... легче на примере показать. Допустим есть класс:
R>В реальности ещё приходится делать поправку на выравнивание, но это уже детали.
Каким образом делается поправка на выравнивание?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
"В любое мгновение принятия решения, лучшее, что вы можете сделать, это принять правильное решение; следующим лучшим вариантом будет принять неправильное решение, худший вариант – не принимать решения совсем" (c) Теодор Рузвельт.
Re[4]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Аноним, Вы писали:
А>Т.е. поиск имен, по-твоему, зависит от того, сколько ты раз написал magic<> ?
поиск имен зависит от того, какие аргументы принимает функция.
если функия принимает аргументом magic, то поиск подходящей функции будет происходит и в пространстве magic.
до инстанцирования magic<-1> есть только engine(...);
после добавляется engine(magic<-1>);
А>Или я не так тебя понял?
похоже на то.
Re[5]: Невероятно, но факт! Не константные значения в компай
От:
Аноним
Дата:
07.02.07 10:12
Оценка:
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, Аноним, Вы писали:
А>>Т.е. поиск имен, по-твоему, зависит от того, сколько ты раз написал magic<> ?
NB>поиск имен зависит от того, какие аргументы принимает функция. NB>если функия принимает аргументом magic, то поиск подходящей функции будет происходит и в пространстве magic.
NB>до инстанцирования magic<-1> есть только engine(...); NB>после добавляется engine(magic<-1>);
А ты не думал, что поиск имен не зависит от инстанцирования и вещи это ортогональные?
А>>Или я не так тебя понял?
NB>похоже на то.
Ну так поясни, почему похоже. Т.е. по твоим представлениям, С++ это язык в котором
void fun()
{
name;
name;
}
поиск имени name зависит от того, в какой оно строке стоит?
Re: Невероятно, но факт! Не константные значения в компайл-т
R>char engine(...);
R>template<typename, int> struct magic;
R>typedef magic<char, -1> magicc;
R>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>struct magic
R>{
R> friend int engine(magicc&, type&);
R> static const int val = id;
R>};
R>int main()
R>{
R> char a[magic<>::val != magic<>::val ? 1 : -1];
R>}
R>
[]
как я понял каждое выражение magic<>::val должно инстанциировать magic заново и sizeof(engine(*(magicc*)0, *(type*)0)) выдавать новые значение?
Все равно не очень понятно
Re: Невероятно, но факт! Не константные значения в компайл-т
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>>Хм... Оригинально, но не понятно, должно ли это работать так, как задумано. Как известно, friend declaration не вводит в охватывающий namespace видимого имени. Поэтому не ясно, почему в твоем случае при второй инстанциации 'magic' lookup для дефолтного аргумента вдруг должно найти именно "друга", а не явно объявленную оригинальную версию 'engine'...
R>Да, friend declaration не вводит в охватывающий namespace видимого имени. Всё правильно. Над этой проблемой пришлось побороться. R>На помощь пришёл ADL! Смотри:
R>
R>Это же работает, хотя тоже вроде как не должно, т.к. operator + () вообще говоря не виден вне класса.
R>Поэтому я добавил в функцию engine() параметр magic&! Теперь она тоже попадает в рассмотрение!
С чего бы это? У тебя тип параметра не совпадает с типом, в котором продекларирован engine().
Здравствуйте, Аноним, Вы писали:
NB>>до инстанцирования magic<-1> есть только engine(...); NB>>после добавляется engine(magic<-1>);
А>А ты не думал, что поиск имен не зависит от инстанцирования и вещи это ортогональные?
похоже у моего любимого компилятора на этот счет есть свое мнение
Re[7]: Невероятно, но факт! Не константные значения в компай
От:
Аноним
Дата:
07.02.07 12:31
Оценка:
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, Аноним, Вы писали:
NB>>>до инстанцирования magic<-1> есть только engine(...); NB>>>после добавляется engine(magic<-1>);
А>>А ты не думал, что поиск имен не зависит от инстанцирования и вещи это ортогональные?
NB> NB>похоже у моего любимого компилятора на этот счет есть свое мнение
Дак это-то понятно, что это особенности компилятора.
Re[8]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Аноним, Вы писали:
А>>>А ты не думал, что поиск имен не зависит от инстанцирования и вещи это ортогональные?
NB>> NB>>похоже у моего любимого компилятора на этот счет есть свое мнение
А>Дак это-то понятно, что это особенности компилятора.
назови хоть один, который компилит правильно
Re[5]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, Аноним, Вы писали: А>>Т.е. поиск имен, по-твоему, зависит от того, сколько ты раз написал magic<> ? NB>поиск имен зависит от того, какие аргументы принимает функция. NB>если функия принимает аргументом magic, то поиск подходящей функции будет происходит и в пространстве magic.
Вообще-то говоря у тебя не совсм так написано...
у тебя engine в глобальном пространстве вроде. Это эе друг?
А ещё, кстати, в оюласть поиска имён входит не сам тип аргумента, а пространство, где он был объявлен..
Так что я, например, не понял, от чего это всё должно работать.
И главное. Я так и не смог найти где же подстановка аргументов шаблона либо формирование списка областей где искать, зависит от того, какие шаблоны уже ьыли инстанциированы.
ИМХО ты пользуешься дыркой в стандарте, когда ты объявляешь, фактически шаблонную функцию, как нешаблонную.
template<typename T>
class FriendFake {
friend void foo( T ) {}
};
Вроде как мы при инстанциировании шаблона FriendFake за одно породили нешаблонную функцию foo.
(Почему нешаблонную? Да потому что при её вызове не будет явно или неявно выводится параметры шаблона)
ИМХО поиск и участие таких функций в разрешении неоднозначнойстей при вызове -- нифига в шаблоне не специфицированы и являются особенностью реализации шаблонов в компилятрое
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, night beast, Вы писали:
NB> NB>похоже у моего любимого компилятора на этот счет есть свое мнение
Будь твёрд в своей любви!
Это соркк особенности обсуждаемого кода!
В целом хотелось бы узнать почему автору кажется, что это чмстый и стандартный C++...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Erop, Вы писали:
E>Вообще-то говоря у тебя не совсм так написано... E>у тебя engine в глобальном пространстве вроде. Это эе друг? E>А ещё, кстати, в оюласть поиска имён входит не сам тип аргумента, а пространство, где он был объявлен..
Здравствуйте, Lorenzo_LAMAS, Вы писали:
E>>В целом хотелось бы узнать почему автору кажется, что это чмстый и стандартный C++...
L_L>Ну, он этого вроде и не утверждал.
Аааа, утверждал, я разглядел теперь.
Не нравятся мне подобные кошмарики на С++
Of course, the code must be complete enough to compile and link.
Re: А INTERNAL COMPILER ERROR тоже вызывает ажиотаж?
Идея в том, что ты хочешь шаблонно заводить нешаблонную функцию в глобальном пространстве имён. Типа так:
template<typename T>
class FriendHack {
friend foo( T ) { } // разве foo -- шаблонная?
};
АФАИК foo -- она не шаблонная. И где она там получается определённой и как и когда появится при поиске кандидатов, при разрешении неоднозначноти вроде никак не гарантируется.
Соответсвенно, если тебе кажется, что это стандартное поведение, то не плохо бы было сделать две вещи
1) Найти где в стандарте описано, как это должно работать.
2) Написать простой пример и проверить работает ли это... додаток1
Возможный контрольный пример:
додаток2
За то, что я прав, голосует ещё и то, что даже у M$ не всё так классно. Если бы всё было так, как ты думаешь, то в функции engine вроде как не был бы нужен второй аргумент...
Увы, в этот раз, похоже, опять не получилось
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Невероятно, но факт! Не константные значения в компай
E>И главное. Я так и не смог найти где же подстановка аргументов шаблона либо формирование списка областей где искать, зависит от того, какие шаблоны уже ьыли инстанциированы.
+1.
Of course, the code must be complete enough to compile and link.
Re: Невероятно, но факт! Не константные значения в компайл-т
Здравствуйте, remark, Вы писали:
R>Сейчас вы увидите, как на стандартном с++ можно иметь переменные значения в компайл-тайм!
Это не стандартный C++
7.3.1.2/3
Every name first declared in a namespace is a member of that namespace. If a friend declaration in a
non-local class first declares a class or function the friend class or function is a member of the innermost
enclosing namespace. The name of the friend is not found by simple name lookup until a matching declaration
is provided in that namespace scope (either before or after the class declaration granting friendship). If
a friend function is called, its name may be found by the name lookup that considers functions from namespaces
and classes associated with the types of the function arguments (3.4.2). When looking for a prior
declaration of a class or a function declared as a friend, and when the name of the friend class or
function is neither a qualified name nor a template-id, scopes outside the innermost enclosing namespace
scope are not considered. [Example:
// Assume f and g have not yet been defined.void h(int);
template <class T> void f2(T);
namespace A {
class X {
friend void f(X); // A::f(X) is a friendclass Y {
friend void g(); // A::g is a friendfriend void h(int); // A::h is a friend
// ::h not consideredfriend void f2<>(int); // ::f2<>(int) is a friend
};
};
// A::f, A::g and A::h are not visible here
X x;
void g() { f(x); } // definition of A::gvoid f(X) { /* ... */} // definition of A::fvoid h(int) { /* ... */ } // definition of A::h
// A::f, A::g and A::h are visible here and known to be friends
}
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Не нравятся мне подобные кошмарики на С++
Не парься!
Это не C++, а просто дырка в стандарте.
Кажется давно уже известная, кстати
Через неё любят хачить убогость шаблонов шестой студии, например
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Невероятно, но факт! Не константные значения в компай
E>Вроде как мы при инстанциировании шаблона FriendFake за одно породили нешаблонную функцию foo. E>(Почему нешаблонную? Да потому что при её вызове не будет явно или неявно выводится параметры шаблона)
Нет эта функцию имеем еще до инстацирования шаблона. А в VC баг. См. 7.3.1.2/3 или http://rsdn.ru/Forum/Message.aspx?mid=2339364&only=1
E>ИМХО поиск и участие таких функций в разрешении неоднозначнойстей при вызове -- нифига в шаблоне не специфицированы и являются особенностью реализации шаблонов в компилятрое
Re[9]: Невероятно, но факт! Не константные значения в компай
От:
Аноним
Дата:
07.02.07 13:39
Оценка:
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, Аноним, Вы писали:
А>>>>А ты не думал, что поиск имен не зависит от инстанцирования и вещи это ортогональные?
NB>>> NB>>>похоже у моего любимого компилятора на этот счет есть свое мнение
А>>Дак это-то понятно, что это особенности компилятора.
NB>назови хоть один, который компилит правильно
Я думаю, Комо, а скорее всего, последний фронт-энд от едг (у Комо он какой-то древний уже). Уж если ЕДГ и глючит, то в совсем уж нетривиальных моментах.
Автор упомянул ЕДГ, но я не понял, что это значит — купить его простым смертным — малореально
Re[10]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, Аноним, Вы писали:
А>>>Дак это-то понятно, что это особенности компилятора.
NB>>назови хоть один, который компилит правильно
А>Я думаю, Комо, а скорее всего, последний фронт-энд от едг (у Комо он какой-то древний уже). Уж если ЕДГ и глючит, то в совсем уж нетривиальных моментах.
Комо считает, что правильным является char engine(...)
что имхо не правильно.
Re[6]: Невероятно, но факт! Не константные значения в компай
реально она нужна только для типа FriendFake<int>.
извне она не видна, но из-за ADL ее можно вызвать.
E>ИМХО поиск и участие таких функций в разрешении неоднозначнойстей при вызове -- нифига в шаблоне не специфицированы и являются особенностью реализации шаблонов в компилятрое
а вот и нет
подробнее C++ Templates: The Complete Guide (11.7 The Barton-Nackman Trick)
Re[11]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, Аноним, Вы писали:
А>>>>Дак это-то понятно, что это особенности компилятора.
NB>>>назови хоть один, который компилит правильно
А>>Я думаю, Комо, а скорее всего, последний фронт-энд от едг (у Комо он какой-то древний уже). Уж если ЕДГ и глючит, то в совсем уж нетривиальных моментах.
NB>Комо считает, что правильным является char engine(...) NB>что имхо не правильно.
Хех, для начала надо попытаться обосновать, почему это неправильно
Кстати, как насчет этого:
вроде как равнозначны. Обе вводят в глобальное пространство имён нешаблонную функцию void foo( int, float )
Так что он вполне объявляет глобальную нешаблонную функцию с параметрами зависящими от того, в какой именно инстанциации шаблона класса она введена.
Как влияют эти функции напоиск кандидатов при разрешении неоднозначностей --
E>>ИМХО поиск и участие таких функций в разрешении неоднозначнойстей при вызове -- нифига в шаблоне не специфицированы и являются особенностью реализации шаблонов в компилятрое NB>а вот и нет NB>подробнее C++ Templates: The Complete Guide (11.7 The Barton-Nackman Trick)
The Barton-Nackman Trick -- то как раз известный. Кто бы спорил.
Но там где объхявляют, там и используют. А тут какие-то одни инстанциации, должны использовать какие-то другие инстанциации. Вроде как никто ничего про это не обещает.
Я вот, что-то не нашёл в стандарте сразу. Не стразу искать лень, так как мне кажется, что и не найду.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[12]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, night beast, Вы писали:
NB>>Здравствуйте, Аноним, Вы писали:
А>>>>>Дак это-то понятно, что это особенности компилятора.
NB>>>>назови хоть один, который компилит правильно
А>>>Я думаю, Комо, а скорее всего, последний фронт-энд от едг (у Комо он какой-то древний уже). Уж если ЕДГ и глючит, то в совсем уж нетривиальных моментах.
NB>>Комо считает, что правильным является char engine(...) NB>>что имхо не правильно.
А>Хех, для начала надо попытаться обосновать, почему это неправильно
попробую. поправь если где ошибся
template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
struct magic
{
friend int engine(magicc&, type&);
static const int val = id;
};
Здравствуйте, Erop, Вы писали:
NB>>реально она нужна только для типа FriendFake<int>. NB>>извне она не видна, но из-за ADL ее можно вызвать.
E>Да вот и нет! E>Вот скажи, декларация E>
void foo( FriendFake<int>, FriendFake<float> );
E>Объявляет шаблон функции разве?
вот здесь я не совсем понял вопроса
E>А ведь декларации E>
E>вроде как равнозначны. Обе вводят в глобальное пространство имён нешаблонную функцию void foo( int, float )
E>Так что он вполне объявляет глобальную нешаблонную функцию с параметрами зависящими от того, в какой именно инстанциации шаблона класса она введена.
да. здесь идет декларация глобальной функции.
но если ты во френде задашь и тело, то она уже будет принадлежать только тому классу, в котором появилась.
E>Как влияют эти функции напоиск кандидатов при разрешении неоднозначностей --
E>>>ИМХО поиск и участие таких функций в разрешении неоднозначнойстей при вызове -- нифига в шаблоне не специфицированы и являются особенностью реализации шаблонов в компилятрое NB>>а вот и нет NB>>подробнее C++ Templates: The Complete Guide (11.7 The Barton-Nackman Trick) E>The Barton-Nackman Trick -- то как раз известный. Кто бы спорил. E>Но там где объхявляют, там и используют. А тут какие-то одни инстанциации, должны использовать какие-то другие инстанциации. Вроде как никто ничего про это не обещает.
ну сэкономил человек на объявлении, что вы привязались.
суть то не в этом.
Re[9]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, night beast, Вы писали:
NB>ну сэкономил человек на объявлении, что вы привязались. NB>суть то не в этом.
Э-э-э где и на чём съкономил?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Невероятно, но факт! Не константные значения в компайл-т
g++ (GCC) 3.4.5 (mingw special)
Нет обещанного чуда:
C:\tect>g++ -Wall -o "mag" "mag.cpp"
mag.cpp:13: warning: friend declaration `int engine(magicc&, type&)' declares a non-template function
mag.cpp:13: warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning
mag.cpp: In function `int main()':
mag.cpp:21: warning: unused variable 'a'
Re[10]: Невероятно, но факт! Не константные значения в компа
если не обращать внимание на синтаксические ляпы, то какое поведение ожидается?
гсс 3.4 выводит noyes, что на мой взгляд некорректно.
E>додаток2 E>За то, что я прав, голосует ещё и то, что даже у M$ не всё так классно. Если бы всё было так, как ты думаешь, то в функции engine вроде как не был бы нужен второй аргумент...
если я правильно понимаю, второй аргумент нужен чтобы сделать вызов функии engine зависящим от параменра шаблона. это должно предотвратить подстановку функии сразу при обявлении.
Re[11]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, night beast, Вы писали:
NB>>>ну сэкономил человек на объявлении, что вы привязались.
NB>
NB>friend int engine(magicc&, type&);
NB>
NB>на { return 0; }
Наверное речь шла об определнии?
Но в целом, ИМХО, это всё не важно, так как реальных вызовов функции engine нет, так что и тел нигде не останется.
А то, что "друг с телом" попадёт только вместе с объемлещим классом, то там же как раз аргумент вроде как второй для того есть.
Так что тело вроде не должно бы было помешать
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: А INTERNAL COMPILER ERROR тоже вызывает ажиотаж?
Здравствуйте, night beast, Вы писали:
NB>гсс 3.4 выводит noyes, что на мой взгляд некорректно.
Я думаю, что это дырка в стандарте. Может быть как угодно
Хотя может если полистать повнимательнее, то этот случае где-то в стандарте расталкован явно. Просто я быстро не нашёл, а долго искать не стал.
NB>если я правильно понимаю, второй аргумент нужен чтобы сделать вызов функии engine зависящим от параменра шаблона. это должно предотвратить подстановку функии сразу при обявлении.
А там однохренственно первый аргумент от параметра вроде зависит. Так что всё равно имя зависимое получается и сразу подставляться не должно бы...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: А INTERNAL COMPILER ERROR тоже вызывает ажиотаж?
Здравствуйте, Erop, Вы писали:
NB>>гсс 3.4 выводит noyes, что на мой взгляд некорректно. E>Я думаю, что это дырка в стандарте. Может быть как угодно
E>Хотя может если полистать повнимательнее, то этот случае где-то в стандарте расталкован явно. Просто я быстро не нашёл, а долго искать не стал.
я опираюсь на книгу Вандервуда. но там к сожалению (или к счастью) ссылки на стандарт нет.
NB>>если я правильно понимаю, второй аргумент нужен чтобы сделать вызов функии engine зависящим от параменра шаблона. это должно предотвратить подстановку функии сразу при обявлении.
E>А там однохренственно первый аргумент от параметра вроде зависит. Так что всё равно имя зависимое получается и сразу подставляться не должно бы...
не, первый там фиксированый: magic<char,-1>
Re[12]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, Erop, Вы писали:
NB>>>>ну сэкономил человек на объявлении, что вы привязались.
NB>>
NB>>friend int engine(magicc&, type&);
NB>>
NB>>на { return 0; }
E>Наверное речь шла об определнии?
да, именно. совсем заврался
E>Но в целом, ИМХО, это всё не важно, так как реальных вызовов функции engine нет, так что и тел нигде не останется. E>А то, что "друг с телом" попадёт только вместе с объемлещим классом, то там же как раз аргумент вроде как второй для того есть. E>Так что тело вроде не должно бы было помешать
без тела оно считается вроде как глобальным а здесь
Здравствуйте, night beast, Вы писали:
NB>я опираюсь на книгу Вандервуда. но там к сожалению (или к счастью) ссылки на стандарт нет.
Книга хорошая.
Только там не всё понятно как оно должно быть.
Ещё раз повторюсь. Ситауция крайне мутная. Как будут взаимодействовать побочные последствия независимых инстанциаций шаблонов.
E>>А там однохренственно первый аргумент от параметра вроде зависит. Так что всё равно имя зависимое получается и сразу подставляться не должно бы...
NB>не, первый там фиксированый: magic<char,-1>
Упс, точно.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Невероятно, но факт! Не константные значения в компайл-т
Здравствуйте, remark, Вы писали:
R>Так вот, всё это неправда! R>Сейчас вы увидите, как на стандартном с++ можно иметь переменные значения в компайл-тайм!
R>char engine(...);
R>template<typename, int> struct magic;
R>typedef magic<char, -1> magicc;
R>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>struct magic
R>{
R> friend int engine(magicc&, type&);
R> static const int val = id;
R>};
R>int main()
R>{
R> char a[magic<>::val != magic<>::val ? 1 : -1];
R>}
вопрос по выделенному. при замене *(magicc*)0 на magicc() получаем одинаковые magic<>::val.
чем вызвано?
ну и в magic<char,-1>::engine второй аргумент char.
Re[10]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, Аноним, Вы писали:
А>Я думаю, Комо, а скорее всего, последний фронт-энд от едг (у Комо он какой-то древний уже). Уж если ЕДГ и глючит, то в совсем уж нетривиальных моментах. А>Автор упомянул ЕДГ, но я не понял, что это значит — купить его простым смертным — малореально
Здравствуйте, Erop, Вы писали:
E>В целом хотелось бы узнать почему автору кажется, что это чмстый и стандартный C++...
А почему нет?
Априори (без ссылок на стандарт) компилирование 3 самыми популярными и приближенными к стандарту компиляторами чего-то да стоит. По крайней мере того, что бы оппонент представил хотя бы какие-то факты, а не просто фразы, что это типа какая-то там некая давно известная дыра где-то
Здравствуйте, Erop, Вы писали:
E>И главное. Я так и не смог найти где же подстановка аргументов шаблона либо формирование списка областей где искать, зависит от того, какие шаблоны уже ьыли инстанциированы.
Ну а какие варианты могут быть?
У меня один вариант — зависимые аргументы шаблона по-умолчанию вычисляются в точке инстанциирования. И соответственно на это вычисление влияет всё, что видно в этой точке. К тому же по аналогии с аргументами функции по-умолчанию.
У тебя есть ещё какие-то разумные варианты?
E>ИМХО ты пользуешься дыркой в стандарте, когда ты объявляешь, фактически шаблонную функцию, как нешаблонную.
Вот это вообще не понял.
Да, я просто объявляю нешаблонную функцию, но при этом никакими дырками не пользуюсь.
Примеры таких объявлений можно увидеть и у Страуструпа, и у Саттера и у др.
E>Вроде как мы при инстанциировании шаблона FriendFake за одно породили нешаблонную функцию foo. E>(Почему нешаблонную? Да потому что при её вызове не будет явно или неявно выводится параметры шаблона)
Да, так всё и есть. Никаких проблем я не вижу.
E>ИМХО поиск и участие таких функций в разрешении неоднозначнойстей при вызове -- нифига в шаблоне не специфицированы и являются особенностью реализации шаблонов в компилятрое
При разрешении перегрузки участвуют все видимые функции. Понятия "таких" функций в стандарте вообще нет, там есть просто функции.
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Здравствуйте, remark, Вы писали:
R>>Сейчас вы увидите, как на стандартном с++ можно иметь переменные значения в компайл-тайм! PC>Это не стандартный C++ PC>[q] PC>7.3.1.2/3
PC>Every name first declared in a namespace is a member of that namespace. If a friend declaration in a PC>non-local class first declares a class or function the friend class or function is a member of the innermost PC>enclosing namespace. The name of the friend is not found by simple name lookup until a matching declaration PC>is provided in that namespace scope (either before or after the class declaration granting friendship). If PC>a friend function is called, its name may be found by the name lookup that considers functions from namespaces PC>and classes associated with the types of the function arguments (3.4.2). When looking for a prior PC>declaration of a class or a function declared as a friend, and when the name of the friend class or PC>function is neither a qualified name nor a template-id, scopes outside the innermost enclosing namespace PC>scope are not considered. [Example:
Не понял мысль.
По-моему, эта цитата подтверждает работоспособность моего кода.
Да, я объявляю все дружественные функции в глобальном пространстве имён. Всё правильно.
Да, потом я её нахожу, т.к. тип параметра функции есть сам этот класс (если быть совсем точным, то не сам этот класс, а другая специализация этого же шаблона, но касательно областей видимости имён это ничего не меняет).
Здравствуйте, Erop, Вы писали:
E>Да вот и нет! E>Вот скажи, декларация E>
void foo( FriendFake<int>, FriendFake<float> );
E>Объявляет шаблон функции разве?
Что ты привязался к шаблонам функции? Да, я их не объявлял и не собирался объявлять. И это ни о чём не говорит. Это никак не влияет на работоспособность кода.
E>вроде как равнозначны. Обе вводят в глобальное пространство имён нешаблонную функцию void foo( int, float ) E>Так что он вполне объявляет глобальную нешаблонную функцию с параметрами зависящими от того, в какой именно инстанциации шаблона класса она введена.
Да, всё так и есть. В чём проблема?
E>Как влияют эти функции напоиск кандидатов при разрешении неоднозначностей --
Так же как и всё остальные.
Нет понятия каких-то "других" функций, есть просто функции и они все равнозначны и одинакого влияют на разрешение перегрузки.
Здравствуйте, np9mi7, Вы писали:
N>Здравствуйте, remark, Вы писали:
R>>3. ... не знаю как назвать... легче на примере показать. Допустим есть класс:
R>>В реальности ещё приходится делать поправку на выравнивание, но это уже детали.
N>Каким образом делается поправка на выравнивание?
Здравствуйте, Константин Л., Вы писали:
КЛ>как я понял каждое выражение magic<>::val должно инстанциировать magic заново и sizeof(engine(*(magicc*)0, *(type*)0)) выдавать новые значение? КЛ>Все равно не очень понятно
Если на пальцах, то примерно так:
При каждом упоминании magic<>::val заного вычисляется значение аргумента по-умолчанию, причём вычисляется оно именно в той точке, где написано magic<>::val.
И выдаёт это вычисление разные результаты, т.к. предыдущая специализация magic внесла новую перегрузку функции engine.
Как-то так...
Здравствуйте, Roman Odaisky, Вы писали:
NB>>вопрос по выделенному. при замене *(magicc*)0 на magicc() получаем одинаковые magic<>::val. NB>>чем вызвано?
RO>это-то понятно. rvalue не привязывается к неконстантной ссылке. Здесь кошернее всего писать так:
да, так понятней.
в принципе, второй параметр не нужен:
template<typename type = int, int id = sizeof( engine( make< magic<type,-1> >() ) ) >
struct magic {
friend int engine( magic<type,-1> );
static const int val = id;
};
Re[3]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>Не понял мысль. R>По-моему, эта цитата подтверждает работоспособность моего кода. R>Да, я объявляю все дружественные функции в глобальном пространстве имён. Всё правильно. R>Да, потом я её нахожу, т.к. тип параметра функции есть сам этот класс (если быть совсем точным, то не сам этот класс, а другая специализация этого же шаблона, но касательно областей видимости имён это ничего не меняет).
R>
typedef struct {} _false;
typedef struct {} _true;
char engine( ... );
template<int id = sizeof( engine( _true() ) )>
struct magic
{
friend int engine(_true);
static const int val = id; //*
};
int main()
{
char a[magic<>::val != magic<>::val ? 1 : -1];
}
friend int engine(_true); в magic<int> объявляет функцию в глобальном пространстве еще до инстанирования шаблона согласно 7.3.1.2/3, поэтому код абсолютно равнозначен этому:
typedef struct {} _false;
typedef struct {} _true;
char engine( ... );
int engine(_true);
template<int id = sizeof( engine( _true() ) )>
struct magic
{
static const int val = id; //*
};
int main()
{
char a[magic<>::val != magic<>::val ? 1 : -1];
}
Именно поэтому на комо это не работает. В VC же баг, там он действительно добавляется лишь после инстанцирования.
Re[2]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Шахтер, Вы писали:
Ш>Здравствуйте, remark, Вы писали:
R>>Пришло время очередного ресёрча
Ш>Хочу влить свою бочку дегтя в эту ложку сахарного сиропа.
Ш>1) Я пока не увидел доказательства того, что это standard-compliant поведение. По-моему -- баг.
Какие моменты у тебя вызывают недоверие?
Ш>2) Если это не баг, то это дыра в стандарте. Срочно фиксить стандарт.
Почему?
Ш>3) Пользоваться такими изобретениями в реальной работе категорически нельзя. Ломиком по рукам.
С такими тезисами обращайся в Философию, там можно такое обсудить на пару сотен постов Или лучше сразу в холивары Покрайней мере к С++ это отношения не имеет.
Здравствуйте, night beast, Вы писали:
NB>Здравствуйте, remark, Вы писали:
R>>Так вот, всё это неправда! R>>Сейчас вы увидите, как на стандартном с++ можно иметь переменные значения в компайл-тайм!
NB>
R>>char engine(...);
R>>template<typename, int> struct magic;
R>>typedef magic<char, -1> magicc;
R>>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>>struct magic
R>>{
R>> friend int engine(magicc&, type&);
R>> static const int val = id;
R>>};
R>>int main()
R>>{
R>> char a[magic<>::val != magic<>::val ? 1 : -1];
R>>}
NB>
NB>вопрос по выделенному. при замене *(magicc*)0 на magicc() получаем одинаковые magic<>::val. NB>чем вызвано?
Чем компилил? Это вообще не должно компилироваться, т.к. ты пытаешься сделать вызов конструктора до определения класса. Там, где ты написал magicc() видно только форвард объявление класса...
T>C:\tect>g++ -Wall -o "mag" "mag.cpp"
T>mag.cpp:13: warning: friend declaration `int engine(magicc&, type&)' declares a non-template function
T>mag.cpp:13: warning: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning
T>mag.cpp: In function `int main()':
T>mag.cpp:21: warning: unused variable 'a'
T>
Что ты имеешь в виду?
Да, gcc выдал пару вполне законных варнингов, но они не то что бы особо принципиальные. Если они тебе сильно мешают — можешь их пофиксить...
Здравствуйте, Pavel Chikulaev, Вы писали:
PC>Здравствуйте, remark, Вы писали:
R>>Не понял мысль. R>>По-моему, эта цитата подтверждает работоспособность моего кода. R>>Да, я объявляю все дружественные функции в глобальном пространстве имён. Всё правильно. R>>Да, потом я её нахожу, т.к. тип параметра функции есть сам этот класс (если быть совсем точным, то не сам этот класс, а другая специализация этого же шаблона, но касательно областей видимости имён это ничего не меняет).
R>>
PC>Объясню на примере IROVа http://rsdn.ru/Forum/Message.aspx?mid=2338001&only=1
Во-первых, тут ошибка, т.к. friend engine() не должна находится без ADL, т.е. это бы при любом раскладе не стало бы работать. Но это так мелочи.
PC>friend int engine(_true); в magic<int> объявляет функцию в глобальном пространстве еще до инстанирования шаблона согласно 7.3.1.2/3, поэтому код абсолютно равнозначен этому: PC>
Нет, это абсолютно не равнозначно.
PC>Именно поэтому на комо это не работает. В VC же баг, там он действительно добавляется лишь после инстанцирования.
Подсказка 1.
template<typename type>
struct magic
{
friend int engine(type);
};
Сколько это определение шаблонного класса должно _сразу_ вынести функций в глобальное пространство имён? Для всего бесконечного возможного набора типов, которыми когда-либо могут параметризовать этот шаблон?
Подсказка 2.
Подумай о POI. Когда в первый раз компилятор начинает компилировать специализацию шаблона. И когда он действительно видет, что какую-то функцию надо выносить в глобальное пространство, и видит какую именно. До POI, т.е. пока не требуется определения класса, компилятор не то что не обязан, он не может компилировать специализацию.
template<typename type = int, int id = sizeof( engine( new magic<type,-1> ) ) >
struct magic {
friend int engine( magic<type,-1> * );
static const int val = id;
};
Re[3]: Невероятно, но факт! Не константные значения в компай
От:
Аноним
Дата:
08.02.07 08:11
Оценка:
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Шахтер, Вы писали:
Ш>>Здравствуйте, remark, Вы писали:
R>>>Пришло время очередного ресёрча
Ш>>Хочу влить свою бочку дегтя в эту ложку сахарного сиропа.
Ш>>1) Я пока не увидел доказательства того, что это standard-compliant поведение. По-моему -- баг.
R>Какие моменты у тебя вызывают недоверие?
Для начала — разыменование нулевого указателя.
R>Почему?
Ты что, серьезно считаешь, что поиск имен зависит от того, что было инстанцировано, а что нет?
Ш>>3) Пользоваться такими изобретениями в реальной работе категорически нельзя. Ломиком по рукам.
R>С такими тезисами обращайся в Философию, там можно такое обсудить на пару сотен постов Или лучше сразу в холивары Покрайней мере к С++ это отношения не имеет.
Код с UB уже тоже.
Re[5]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Sm0ke, Вы писали:
S>А почему не зделать так?: S>
S>template<typename type = int, int id = sizeof( engine( new magic<type,-1> ) ) >
S>struct magic {
S> friend int engine( magic<type,-1> * );
S> static const int val = id;
S>};
S>
Повторяешь ошибку Chez'a и Gurtovoy — с указателем функция не будет находится по ADL
R>Сколько это определение шаблонного класса должно _сразу_ вынести функций в глобальное пространство имён? Для всего бесконечного возможного набора типов, которыми когда-либо могут параметризовать этот шаблон?
Да именно так, т.е. равнозначно этому (кроме прав доступа)
template<typename type>
int engine(type);
template<typename type>
struct magic
{
};
R>Подумай о POI. Когда в первый раз компилятор начинает компилировать специализацию шаблона. И когда он действительно видет, что какую-то функцию надо выносить в глобальное пространство, и видит какую именно. До POI, т.е. пока не требуется определения класса, компилятор не то что не обязан, он не может компилировать специализацию.
Это единственное исключение, но это так, т.е. компилятор должен пропускать все в шаблоне кроме друзей.
Re[5]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Lorenzo_LAMAS, Вы писали:
R>>Можно поподробнее и поаргументированнее.
L_L>А ты комо онлайн запусти в стрикт режиме и увидишь много интересного.
"ComeauTest.c", line 9: warning: "int engine(magicc &, type &)" declares a
non-template function -- add <> to refer to a template instance
friend int engine(magicc&, type&);
^
Пожалуйста, мне не жалко
"ComeauTest.c", line 15: error: the size of an array must be greater than zero
char a[magic<>::val != magic<>::val ? 1 : -1];
^
Ошибка ни о чём не говорит. Где и что конкретно не так.
"ComeauTest.c", line 15: warning: variable "a" was declared but never referenced
char a[magic<>::val != magic<>::val ? 1 : -1];
^
Уж вот этому точно не равнозначно. Однозначно.
Тут шаблонная функция, а у меня не шаблонная. А это две большие разницы.
R>>Подумай о POI. Когда в первый раз компилятор начинает компилировать специализацию шаблона. И когда он действительно видет, что какую-то функцию надо выносить в глобальное пространство, и видит какую именно. До POI, т.е. пока не требуется определения класса, компилятор не то что не обязан, он не может компилировать специализацию. PC>Это единственное исключение, но это так, т.е. компилятор должен пропускать все в шаблоне кроме друзей.
А можно ссылку на стандарт или ещё куда-то?
А если друг в шаблонном клсее, который вложен в другой шаблонный класс???... Ему придётся компилировать ещё и вложенный шаблонный класс??? ... Если вложенный шаблонный класс как-то хитро зависит от параметров шаблона объемлющего?...
Не очень понятно, как это должно/может работать...
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Аноним, Вы писали:
А>>Я думаю, Комо, а скорее всего, последний фронт-энд от едг (у Комо он какой-то древний уже). Уж если ЕДГ и глючит, то в совсем уж нетривиальных моментах. А>>Автор упомянул ЕДГ, но я не понял, что это значит — купить его простым смертным — малореально
R>EDG C++ это компилирует R>здесь
R>
Хехе, у них версия фронт-энда старее, чем у Комо онлайн.
Of course, the code must be complete enough to compile and link.
Re[3]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
NB>>вопрос по выделенному. при замене *(magicc*)0 на magicc() получаем одинаковые magic<>::val. NB>>чем вызвано?
R>Чем компилил?
гсс 3.4
R>Это вообще не должно компилироваться, т.к. ты пытаешься сделать вызов конструктора до определения класса. Там, где ты написал magicc() видно только форвард объявление класса...
а не при создании первой переменной?
Re[3]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, remark, Вы писали:
R>>Здравствуйте, Шахтер, Вы писали:
Ш>>>Здравствуйте, remark, Вы писали:
R>>>>Пришло время очередного ресёрча
Ш>>>Хочу влить свою бочку дегтя в эту ложку сахарного сиропа.
Ш>>>1) Я пока не увидел доказательства того, что это standard-compliant поведение. По-моему -- баг.
R>>Какие моменты у тебя вызывают недоверие?
А>Для начала — разыменование нулевого указателя.
Пуристы могут заменить это разыменование на вызов функции:
magicc& get_some_magic();
R>>Почему?
А>Ты что, серьезно считаешь, что поиск имен зависит от того, что было инстанцировано, а что нет?
Я серьёзно считаю, что поиск имён зависит от того, что видно в POI.
Ш>>>3) Пользоваться такими изобретениями в реальной работе категорически нельзя. Ломиком по рукам.
R>>С такими тезисами обращайся в Философию, там можно такое обсудить на пару сотен постов Или лучше сразу в холивары Покрайней мере к С++ это отношения не имеет.
А>Код с UB уже тоже.
R>>Это вообще не должно компилироваться, т.к. ты пытаешься сделать вызов конструктора до определения класса. Там, где ты написал magicc() видно только форвард объявление класса...
NB>а не при создании первой переменной?
Нет.
Вот смотри ещё 2 аналогичных примера, которые _не_ работают по той же причине:
template<typename type>
struct b {};
template<typename type>
struct d : b<d::inner>
{
typedef type inner;
};
template<typename type>
struct b
{
typedef typename type::inner inner;
};
template<typename type>
struct d : b<d>
{
};
R>"ComeauTest.c", line 15: error: the size of an array must be greater than zero
R> char a[magic<>::val != magic<>::val ? 1 : -1];
R> ^
R>Ошибка ни о чём не говорит. Где и что конкретно не так.
Да что ты? Она говорит о том, что magic<>::val он один и не меняется. Или нет?
R>Аааа... ты про это мне хотел сказать???
Не, я хотел о другом — забавно, я вчера пробовал — и он орал о разыменовании нулевых указателей. Похоже, что это он замечает в relaxed mode.
А вообще, так как всем нам, похоже, одинаково некогда/лень ковыряться в стандарте и искать обоснований тех или иных утверждений, лучше подождать авторитетных мнений: Андрея Тарасевича, Павла Кузнецова, elcste (порядок указания имен произвольный ). Можно спросить на comp.lang.c++.moderated.
Лично для меня очевидно, что поиск имен должен работать всегда одинаково и не зависеть от того, что и сколько раз инстанцировалось.
Of course, the code must be complete enough to compile and link.
Re[6]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
S>>А почему не зделать так?:
думаю, что в обявлении friend должно быть что-то, что инстанцирует magic<type,-1> (то есть не указатель)
но если friend действительно вводит нужную функцию в глобальное пространство и это корректно, тогда можно и указатель.
S>>
S>>template<typename type = int, int id = sizeof( engine( new magic<type,-1> ) ) >
S>>struct magic {
S>> friend int engine( magic<type,-1> * );
S>> static const int val = id;
S>>};
S>>
R>Повторяешь ошибку Chez'a и Gurtovoy — с указателем функция не будет находится по ADL
да вроде находится.
Re[5]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>>>Это вообще не должно компилироваться, т.к. ты пытаешься сделать вызов конструктора до определения класса. Там, где ты написал magicc() видно только форвард объявление класса...
NB>>а не при создании первой переменной?
R>Нет.
аналогичный пример
template< typename T, typename S> struct test;
template< typename T, typename S = typename test<T,void>::type >
struct test {
typedef int type;
};
int main () {
test<int> x;
}
R>Вот смотри ещё 2 аналогичных примера, которые _не_ работают по той же причине:
не аналогичных. ты тип используешь не в определении default параметра.
Здравствуйте, remark, Вы писали:
R>Априори (без ссылок на стандарт) компилирование 3 самыми популярными и приближенными к стандарту компиляторами чего-то да стоит. По крайней мере того, что бы оппонент представил хотя бы какие-то факты, а не просто фразы, что это типа какая-то там некая давно известная дыра где-то
Ну дыра называется The Barton-Nackman Trick.
Но в этом случае всё происходит изнутри шаблона, всё-таки.
Как именно должны взаимодействовать глобальные функции, объявленные в разных инстанциациях шаблона я в стандарте не нашёл
Может плоъхо искал...
Но в целом, видимо есть, по крайней мере надежда, что стандарт можно и удобно трактовать так, чтобы было счастье. Но будет ли оно --
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Невероятно, но факт! Не константные значения в компайл-т
Здравствуйте, remark, Вы писали:
R>Так же как и всё остальные. R>Нет понятия каких-то "других" функций, есть просто функции и они все равнозначны и одинакого влияют на разрешение перегрузки.
Сутиь проблемы в следующем.
В С++ шаблоны определены очень запутано и непоследовательно. Например, относительно легко написать код, который будет зависеть не только от точки инстанциации шаблона, но ещё и от последовательности этих инстанциаций.
Когда инстанциации связаны между собой, то вроде как всё специфицировано, но вот когда они несвязаны никак, то, АФАИК это не специфицировано.
В принципе это правильно, так как предоставляет довольно полезную свободу авторам компиляторов. Скажем каждый шаблон, с каждым набором параметров хотя бы предсказуемо инстанцируется.
А так, от порядка инстанциации шаблонов в единице трансляции, начнёт зависеть то, что нужно генерить по шаблонам. Это приведёт к проблемам с ODR, например.
Так что, ИМХО и АФАИК это всё-таки особенность реализации шаблонов в используемых тобой компиляторах.
Например, может сломаться на компиляторе, который компилит все шаблоны в одну базу на проект, а потом оттуда их переиспользует, то может и не сработать
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[7]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>Вот это вообще не понял. R>Да, я просто объявляю нешаблонную функцию, но при этом никакими дырками не пользуюсь. R>Примеры таких объявлений можно увидеть и у Страуструпа, и у Саттера и у др.
Дырка состоит в том, что у инстанцирования шаблонного класса есть побочный эффект -- появляется объявление нешаблонной функции в объемлющем пространстве имён. На что именно влияет это объявление,а на что не влияет -- это вопрос очень тонкий.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Невероятно, но факт! Не константные значения в компай
R>Я серьёзно считаю, что поиск имён зависит от того, что видно в POI.
Мне вот тоже влом думать Я написал простой пример:
template<class>
class A
{
friend void fun(const A<char> *);
};
int main()
{
A<char> * p = 0;
fun(p);
}
Комо находит функцию.
Вижуал — лошит — не находит! Зато, если я добавляю
int main()
{
A<int>a;
A<char> *p = 0;
fun(p);
}
Он уже может найти эту функцию. Так вот ты что, утверждаешь, что такое поведение вижуала правильное???
Кстати, а что за бредовую муру пишет вижуал, если сделать так:
int main()
{
A<char> *p = 0;
fun(p);
A<int>a;
}
??
Of course, the code must be complete enough to compile and link.
Re[3]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Шахтер, Вы писали:
Ш>>Здравствуйте, remark, Вы писали:
R>>>Пришло время очередного ресёрча
Ш>>Хочу влить свою бочку дегтя в эту ложку сахарного сиропа.
Ш>>1) Я пока не увидел доказательства того, что это standard-compliant поведение. По-моему -- баг.
R>Какие моменты у тебя вызывают недоверие?
Ш>>2) Если это не баг, то это дыра в стандарте. Срочно фиксить стандарт.
R>Почему?
Потому что нарушаются локальность поведения и принцип однозначности значения шаблона как функции аргументов. Нарушение этих базовых принципов ничем не оправдано.
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Лично для меня очевидно, что поиск имен должен работать всегда одинаково и не зависеть от того, что и сколько раз инстанцировалось.
По-моему, тут не всё так просто.
template <class X>
class C
{
friend void doSomething(X &);
}
Здравствуйте, Lorenzo_LAMAS, Вы писали:
R>>Я серьёзно считаю, что поиск имён зависит от того, что видно в POI.
L_L>Мне вот тоже влом думать Я написал простой пример: L_L>
L_L>Он уже может найти эту функцию. Так вот ты что, утверждаешь, что такое поведение вижуала правильное???
14.6.5/2
[q]
As with non-template classes, the names of namespace-scope friend functions of a class template specialization
are not visible during an ordinary lookup unless explicitly declared at namespace scope (11.4).
Such names may be found under the rules for associated classes (3.4.2).131) [Example:
template<typename T> class number {
public:
number(int);
//...friend number gcd(const number& x, const number& y);
//...void g()
{
number<double> a(3), b(4);
//...
a = gcd(a,b); // finds gcd because number<double> is an
// associated class, making gcd visible
// in its namespace (global scope)
b = gcd(3,4); // ill-formed; gcd is not visible
}
—end example]
};
[/q]
Re[2]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Шахтер, Вы писали:
Ш>1) Я пока не увидел доказательства того, что это standard-compliant поведение. По-моему -- баг. Ш>2) Если это не баг, то это дыра в стандарте. Срочно фиксить стандарт. Ш>3) Пользоваться такими изобретениями в реальной работе категорически нельзя. Ломиком по рукам.
Больше всего это похоже на нарушение ODR.
Вот простенький пример, делающий то же самое абсолютно без наворотов.
char foo(...);
int const x = sizeof(foo(char(0)));
int foo(int);
int const y = sizeof(foo(char(0)));
double foo(char);
int const z = sizeof(foo(char(0)));
Разница лишь в том, что мы не автоматически, а вручную ввели новые определения. Ну и количество уточнений ограничено тремя: char < int < ...
И если это действительно ODR, то программа ill-formed, а поведение компилятора не определено. Тот факт, что большинство компиляторов пошли одним путём — поздравляю.
Могли и не пойти, кстати.
Если компилятор в точке объявления t1 запоминает все дефолтные параметры, доступные на тот момент, то
— t1 != t2
— typeof(x1) == typeof(x2) == typeof(x3)
А если компилятор полагает, что sequence<> и в африке sequence<>, запоминает, что "вот здесь параметры — дефолтные" и затем разворачивает их по месту использования, то
— t1 эквивалентно t2 (т.е. x4...x6 продолжают серию x1...x3)
— typeof(x1) != typeof(x2) != typeof(x3)
Кстати, от VC<=7.0 можно было ожидать именно такого... Раз уж он шаблоны запоминал как AST без проверок.
А особенно прикольно это будет смотреться, когда шаблон дважды встретится в одном выражении. Который будет какой?
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[3]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Шахтер, Вы писали:
Ш>>1) Я пока не увидел доказательства того, что это standard-compliant поведение. По-моему -- баг. Ш>>2) Если это не баг, то это дыра в стандарте. Срочно фиксить стандарт. Ш>>3) Пользоваться такими изобретениями в реальной работе категорически нельзя. Ломиком по рукам.
К>Больше всего это похоже на нарушение ODR. К>Вот простенький пример, делающий то же самое абсолютно без наворотов.
К>char foo(...);
К>int const x = sizeof(foo(char(0)));
К>int foo(int);
К>int const y = sizeof(foo(char(0)));
К>double foo(char);
К>int const z = sizeof(foo(char(0)));
К>Разница лишь в том, что мы не автоматически, а вручную ввели новые определения. Ну и количество уточнений ограничено тремя: char < int < ...
а где здесь нарушение ODR?
объявлено 3 разных функции.
К>И если это действительно ODR, то программа ill-formed, а поведение компилятора не определено. Тот факт, что большинство компиляторов пошли одним путём — поздравляю. К>Могли и не пойти, кстати.
ну, порядок инстанцирования вроде более менее определен. собственно, это и ипользуется.
R>>template<typename type>
R>>struct magic
R>>{
R>> friend int engine(type);
R>>};
R>>Сколько это определение шаблонного класса должно _сразу_ вынести функций в глобальное пространство имён? Для всего бесконечного возможного набора типов, которыми когда-либо могут параметризовать этот шаблон? PC>Да именно так, т.е. равнозначно этому (кроме прав доступа)
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>Априори (без ссылок на стандарт) компилирование 3 самыми популярными и приближенными к стандарту компиляторами чего-то да стоит. По крайней мере того, что бы оппонент представил хотя бы какие-то факты, а не просто фразы, что это типа какая-то там некая давно известная дыра где-то
E>Ну дыра называется The Barton-Nackman Trick. E>Но в этом случае всё происходит изнутри шаблона, всё-таки. E>Как именно должны взаимодействовать глобальные функции, объявленные в разных инстанциациях шаблона я в стандарте не нашёл E>Может плоъхо искал...
Моё мнение такое, что тут никаких особых правил и не надо — всё работает по общим правилам.
E>Но в целом, видимо есть, по крайней мере надежда, что стандарт можно и удобно трактовать так, чтобы было счастье. Но будет ли оно --
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>Так же как и всё остальные. R>>Нет понятия каких-то "других" функций, есть просто функции и они все равнозначны и одинакого влияют на разрешение перегрузки.
E>Сутиь проблемы в следующем. E>В С++ шаблоны определены очень запутано и непоследовательно. Например, относительно легко написать код, который будет зависеть не только от точки инстанциации шаблона, но ещё и от последовательности этих инстанциаций. E>Когда инстанциации связаны между собой, то вроде как всё специфицировано, но вот когда они несвязаны никак, то, АФАИК это не специфицировано. E>В принципе это правильно, так как предоставляет довольно полезную свободу авторам компиляторов. Скажем каждый шаблон, с каждым набором параметров хотя бы предсказуемо инстанцируется. E>А так, от порядка инстанциации шаблонов в единице трансляции, начнёт зависеть то, что нужно генерить по шаблонам. Это приведёт к проблемам с ODR, например.
Вот к проблемам с ODR тут ничего не приведёт.
По факту у меня получается не более, чем:
magic<0>::val;
magic<1>::val;
magic<2>::val;
Такой код можно и руками написать.
Тут ODR _не_ нарушается, и следовательно привести к нарушению ODR в будущем не может. Смотри, например, мою реализацию определения смещения членов в классе — все классы, которые зависят от magic — просто тоже становятся разными классами (точнее разными специализациями).
E>Так что, ИМХО и АФАИК это всё-таки особенность реализации шаблонов в используемых тобой компиляторах. E>Например, может сломаться на компиляторе, который компилит все шаблоны в одну базу на проект, а потом оттуда их переиспользует, то может и не сработать
Каким образом там это сломается? У меня ODR нигде не нарушается. Хоть в одну базу их клади, хоть нет, неважно.
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>Вот это вообще не понял. R>>Да, я просто объявляю нешаблонную функцию, но при этом никакими дырками не пользуюсь. R>>Примеры таких объявлений можно увидеть и у Страуструпа, и у Саттера и у др.
E>Дырка состоит в том, что у инстанцирования шаблонного класса есть побочный эффект -- появляется объявление нешаблонной функции в объемлющем пространстве имён. На что именно влияет это объявление,а на что не влияет -- это вопрос очень тонкий.
Не поленюсь ещё раз переписать пример, который приводят и Страуструп и Саттер и др.:
Я надеюсь его работоспособность не вызывает вопросов. Иначе это уже не ко мне.
Имхо, если повнимательнее поглядеть на пример, то всё становится достаточно прозрачно.
В POI для конкретной специализации friend function выносится в объемлющее пространство. И "ниже" POI эта function может вызываться и участвовать в перегрузке на равне со всеми остальными.
R>>"ComeauTest.c", line 15: error: the size of an array must be greater than zero
R>> char a[magic<>::val != magic<>::val ? 1 : -1];
R>> ^
R>>Ошибка ни о чём не говорит. Где и что конкретно не так.
L_L>Да что ты? Она говорит о том, что magic<>::val он один и не меняется. Или нет?
Ну это-то я понял из ошибки
Но она не говорит о том, где и что конкретно я нарушил из стандарта.
А по поводу глюков конкретного компилятора — так Comeau пока в заметном меньшенстве, т.ч. если у какого компилятора глюки, так это как раз у него
R>>Аааа... ты про это мне хотел сказать???
L_L>Не, я хотел о другом — забавно, я вчера пробовал — и он орал о разыменовании нулевых указателей. Похоже, что это он замечает в relaxed mode.
Ну что вы все к ним прицепились. Я уже написал, пуристы могут заменить на вызов функции, возвращающей ссылку
К сути вопроса это малол относится...
L_L>А вообще, так как всем нам, похоже, одинаково некогда/лень ковыряться в стандарте и искать обоснований тех или иных утверждений, лучше подождать авторитетных мнений: Андрея Тарасевича, Павла Кузнецова, elcste (порядок указания имен произвольный ). Можно спросить на comp.lang.c++.moderated. L_L>Лично для меня очевидно, что поиск имен должен работать всегда одинаково и не зависеть от того, что и сколько раз инстанцировалось.
Я надеюсь его работоспособность не вызывает вопросов. Иначе это уже не ко мне.
Имхо, если повнимательнее поглядеть на пример, то всё становится достаточно прозрачно.
В POI для конкретной специализации friend function выносится в объемлющее пространство. И "ниже" POI эта function может вызываться и участвовать в перегрузке на равне со всеми остальными.
Что здесь вызывает вопросы?
То, что эту функцию можно вызывать "ниже" POI — это факт. А раз можно вызывать, значит она есть, а раз есть, значит она участвует в перегрузке на равне со всеми остальными, т.к. никаких таких особенных функций в языке нет (как тут некоторые пытались предложить), которые можно вызывать, но в перегрузке не участвуют.
Ведь если просто объявить дополнительную перегрузку функции "руками", то ведь будет зависеть до неё делать POI или после. Ведь эта основная суть POI, что шаблон видит всё, что "выше" POI.
R>>>Сколько это определение шаблонного класса должно _сразу_ вынести функций в глобальное пространство имён? Для всего бесконечного возможного набора типов, которыми когда-либо могут параметризовать этот шаблон? PC>>Да именно так, т.е. равнозначно этому (кроме прав доступа) NB>
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, Шахтер, Вы писали:
Ш>>1) Я пока не увидел доказательства того, что это standard-compliant поведение. По-моему -- баг. Ш>>2) Если это не баг, то это дыра в стандарте. Срочно фиксить стандарт. Ш>>3) Пользоваться такими изобретениями в реальной работе категорически нельзя. Ломиком по рукам.
К>Больше всего это похоже на нарушение ODR.
Нет-нет! Подождите!
Где ж тут нарушение ODR? Для какого объявления есть более одного определения???
ODR — это как раз то, с чем пришлось побороться при реализации.
И имхо я его побороол, т.к. у меня получаются просто разные типы. Фактически это равнозначно такому _рукописному_ коду:
magic<0>::val;
magic<1>::val;
magic<2>::val;
Тут очевидно нет никакого нарушения ODR — просто обычный код.
А по поводу того, что написано в аргументе шаблона по-умолчанию — ну так это же аргумент (сравните с параметром)! А аргумент относится к call-side. Т.е. фактически равнозначно:
Нет-нет-нет. Тоже не cогласен.
typdef запоминает конкретный template-id, template он не запоминает. Если аргументы не указаны, значит в template-id используются аргументы по-умолчанию. Всё. Точка.
Тут всё однозначно! Никаких разночтений и вопросов!
Здравствуйте, remark, Вы писали:
Ш>>С чего бы это? У тебя тип параметра не совпадает с типом, в котором продекларирован engine().
и че с того?
если объявление идет в глобально пространство, то все нормально.
если в локальное, то передачу по ссылке в объявлении френда можно заменить на передачу по значению.
R>Отвечаю на конкретный вопрос
R>Похоже тут ты прав. R>Тогда предлагаю сделать так (тут вроде в этом плане всё чисто):
Здравствуйте, Roman Odaisky, Вы писали:
R>>участвует в перегрузке наравне со всеми остальными
RO>Или я что-то путаю, или функции, которые находит только ADL, имеют более низкий приоритет?
увы
сам офигел когда узнал, но простой поиск и ADL имеют одинаковый приоритет.
то есть сначала происходит поиск имен (все поиски) а потом оверлоад ресолюшн.
так что будте осторожны с выборос жадных перегрузок.
Re[8]: Невероятно, но факт! Не константные значения в компай
RO>Зависит ли здесь поиск имен от того, чем инстанцируется C? По-моему, очень даже зависит.
Что ты хотел сказать этим примером-то? Например, я инстанцировал C типом int, что ADL тут сработает? Или каким-то еще классом (и при этом инстанцировал C неважно каким типом) что, ADL тут тебе поможет????
Of course, the code must be complete enough to compile and link.
Re[7]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
К>>Больше всего это похоже на нарушение ODR.
R>Нет-нет! Подождите! R>Где ж тут нарушение ODR? Для какого объявления есть более одного определения???
Мда, действительно... значит, не оно.
Хотя ситуация, когда одно и то же выражение в разных частях одного и того же scope резолвится по-разному — настораживает...
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[11]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Аноним, Вы писали:
А>>Я думаю, Комо, а скорее всего, последний фронт-энд от едг (у Комо он какой-то древний уже). Уж если ЕДГ и глючит, то в совсем уж нетривиальных моментах. А>>Автор упомянул ЕДГ, но я не понял, что это значит — купить его простым смертным — малореально
R>EDG C++ это компилирует R>здесь
R>
Здравствуйте, Lorenzo_LAMAS, Вы писали:
RO>>Зависит ли здесь поиск имен от того, чем инстанцируется C? По-моему, очень даже зависит.
L_L>Что ты хотел сказать этим примером-то? Например, я инстанцировал C типом int, что ADL тут сработает? Или каким-то еще классом (и при этом инстанцировал C неважно каким типом) что, ADL тут тебе поможет????
Я не об этом… Если компилятор видит someFunctionDeclaredAsFriend_OrPerhapsNotYet_(someExpr()), то его понимание этого зависит от того, чем инстанцировался класс ранее по ходу и инстанцировался ли вообще. Например:
Здравствуйте, night beast, Вы писали:
R>>>участвует в перегрузке наравне со всеми остальными
RO>>Или я что-то путаю, или функции, которые находит только ADL, имеют более низкий приоритет?
NB>увы NB>сам офигел когда узнал, но простой поиск и ADL имеют одинаковый приоритет. NB>то есть сначала происходит поиск имен (все поиски) а потом оверлоад ресолюшн. NB>так что будте осторожны с выборос жадных перегрузок.
А как же 3.4.2/2a («If the ordinary unqualified lookup of the name finds the declaration of a class member function, the associated namespaces and classes are not considered»)? Хотя тут тоже неясно — причем здесь цласс мембер фунцтион?
Я поскипал твои примеры, извини, но мне уже влом их смотреть, так же как и тебе, видимо, влом понять, о чем я говорю. Поиск имен, АДЛ _не_ _зависят_ от того, писал ли ты A<someType> строчкой выше до fun(somArg). АДЛ зависит от типа somArg. И используя этот тип АДЛ найдет нужную функцию и без A<someType> строчкой выше. Я говорил об этом. И magic<>::val повторенный сколько угодно раз в этом злосчастном объявлении массива будет одним и тем же. И если у Вижуала это не так — это его проблемы и тех, кто хочет юзать такие трики.
Of course, the code must be complete enough to compile and link.
Re[11]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, Roman Odaisky, Вы писали:
RO>А как же 3.4.2/2a («If the ordinary unqualified lookup of the name finds the declaration of a class member function, the associated namespaces and classes are not considered»)? Хотя тут тоже неясно — причем здесь цласс мембер фунцтион?
по счастью это можно проверить.
template<typename T> void foo (T,T);
namespace ns {
struct test {};
template<typename T> void foo (T,T);
}
int main () {
ns::test x;
foo (x,x);
}
ИМХО.
После того, как здесь не менее 10 раз упомянули, что friend объявление не добавляет имя, которое может найти обычный поиск имен (не АДЛ), странно писать testy1(x) — почему тут что-то должно быть найдено? testy0() а почему тут?
А уж про нахождения имен после инстанцирования старыми версиями gcc и вижуалом — вообще говорить надоело.
Of course, the code must be complete enough to compile and link.
Так как у тебя нет объявлений функций друзей вне классов, то работать будет только то, что найдет ADL. Про ADL — читай в стандарте.
Выражения, где ты берешь адрес функции — есс-но не компилируются, т.к. не имеют к АДЛ никакого отношения. Выражения с квалификацией — тоже.
When an unqualified name is used as the postfix-expression in a function call (5.2.2), other namespaces not
considered during the usual unqualified lookup (3.4.1) may be searched, and namespace-scope friend function
declarations (11.4) not otherwise visible may be found.
#include <iostream>
namespace ns
{
class X
{
public:
friend void testxx(X const& x)
{
std::cout << "An X: " << &x << std::endl;
}
friend void testx()
{
std::cout << "Just a test." << std::endl;
}
};
}
class Y
{
public:
friend void testyy(Y const& y)
{
std::cout << "A Y: " << &y << std::endl;
}
friend void testy()
{
std::cout << "Just a test." << std::endl;
}
};
int main()
{
ns::X x;
testxx(x);
// ns::testxx(x);
Y y;
testyy(y);
// ::testyy(x);
/* std::cout << (void *)&testy << std::endl;
std::cout << (void *)&testyy << std::endl;
std::cout << (void *)&ns::testx << std::endl;
std::cout << (void *)&ns::testxx << std::endl;
testy();//здесь нет никаких аргументов == не может найти такое имя.
ns::testx();*/
}
Of course, the code must be complete enough to compile and link.
Re[8]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Lorenzo_LAMAS, Вы писали:
L_L>Кстати, на случай, если ты не понял, к чему был мой пример — вот еще один:
L_L>Вижуал выдает странные сообщения об ошибках. У комо все как надо, АДЛ работает. L_L>Вот так вот работает и VC
L_L>Но это ИМХО говорит лишь о некоторой его кривизне, которую и хочет использовать автор исходного сообщения.
В конце концов на комо никто не работает — все работают на gcc/msvc — а у них такая модель компиляции шаблонов
Кстати в бусте тоже присутствуют всякие нехорошие моменты и затычки — но они ориентируются именно на работоспособность кода хотя бы под двумя компиляторами — причём зачастую работа под двумя компиляторами достигается по разному
Здравствуйте, remark, Вы писали:
R>Каким образом там это сломается? У меня ODR нигде не нарушается. Хоть в одну базу их клади, хоть нет, неважно.
У тебя-то ODR не нарушается, но вот, если бы компиляторы работали так, как ты хочешь, то легко бы могла нарушаться.
В этом проблема.
поэтому работать может как-то неожиданно. Ты же довольно тонкой особенностью реализации пользуешься?
НУ а попробовать на трансляторе с общей базой шаблонов я тебе посоветовал потому, что там шаблоны оборабатываются сильно не так, как в GCC, например.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>Я надеюсь его работоспособность не вызывает вопросов. Иначе это уже не ко мне. R>Имхо, если повнимательнее поглядеть на пример, то всё становится достаточно прозрачно. R>В POI для конкретной специализации friend function выносится в объемлющее пространство. И "ниже" POI эта function может вызываться и участвовать в перегрузке на равне со всеми остальными.
Но ты-то немного другой пример написал...
Ты же находишь другой engine, чем подставляемый...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Шахтер, Вы писали:
Ш>>С чего бы это? У тебя тип параметра не совпадает с типом, в котором продекларирован engine().
R>Отвечаю на конкретный вопрос
R>Похоже тут ты прав. R>Тогда предлагаю сделать так (тут вроде в этом плане всё чисто):
Да нет, не будет это работать.
char engine(...);
template<typename type>
struct magic_base
{
friend int engine(magic_base<type>&, type&) {return 0;};
};
template<typename type> type& create();
template<typename type = int, int id = sizeof(engine(create<magic_base<type> >(), create<type>() ))>
struct magic : magic_base<type>
{
static const int val = id;
};
int main()
{
char a[magic<>::val
Эта строчка вызовет следующие действия компилятора
1) magic<> -> magic<int,id> . Вычислить id.
2) id = sizeof ( engine(magic_base<int> &,int &) ) . Найти engine.
3) Первый кандидат -- char engine(...).
4) Включаем ADL. Первый аргумент -- magic_base<int> &. Ищем в пространстве имен magic_base<int>. Для этого инстантинируем magic_base<int>.
5) По ADL находим второго кандидата -- int magic_base<int>::engine(magic_base<int> &,int &).
6) Второй кандидат выигрывает по правилам разрешения перегрузки.
7) id=4
!= magic<>::val ? 1 : -1];
Всё повторится с тем же самым результатом (за тем исключением, что второй раз magic_base<int> инстантинирован не будет).
(void)a;
}
R>char engine(...);
R>template<typename, int> struct magic;
R>typedef magic<char, -1> magicc;
R>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>struct magic
R>{
R> friend int engine(magicc&, type&);
R> static const int val = id;
R>};
R>int main()
R>{
R> char a[magic<>::val != magic<>::val ? 1 : -1];
R>}
R>
Вот смотри. Я так тебя понял что ты ждёшь, что выделенное неравенство будет соблюдено.
Вот и поясни (без всяких там ссылок на тонкости стандарта), как, по твоему мнению обстоит дело.
Где именно и какие именоо инстанциации инстанциируются. То есть укажи пожалуйста место POI для всех участвующих в процессе шаблонов.
А то я что-то никак не въеду
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, remark, Вы писали:
К>>>Больше всего это похоже на нарушение ODR.
R>>Нет-нет! Подождите! R>>Где ж тут нарушение ODR? Для какого объявления есть более одного определения???
К>Мда, действительно... значит, не оно.
К>Хотя ситуация, когда одно и то же выражение в разных частях одного и того же scope резолвится по-разному — настораживает...
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>
R>>char engine(...);
R>>template<typename, int> struct magic;
R>>typedef magic<char, -1> magicc;
R>>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>>struct magic
R>>{
R>> friend int engine(magicc&, type&);
R>> static const int val = id;
R>>};
R>>int main()
R>>{
R>> char a[magic<>::val != magic<>::val ? 1 : -1];
R>>}
R>>
E>Вот смотри. Я так тебя понял что ты ждёшь, что выделенное неравенство будет соблюдено. E>Вот и поясни (без всяких там ссылок на тонкости стандарта), как, по твоему мнению обстоит дело. E>Где именно и какие именоо инстанциации инстанциируются. То есть укажи пожалуйста место POI для всех участвующих в процессе шаблонов.
E>А то я что-то никак не въеду
и почему id должен быть всегда разным? не очевидно.
Re[6]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Шахтер, Вы писали:
Ш>Да нет, не будет это работать.
Совершенно согласен. только формулировочку можно смягчить на "не обязана работать на соответсвующем стандарту комиляторе".
Идея всего хака в том, что в принципе компилятьору никто не запрещает инстанцировать какие-нибудь левые лаблорны, если ему от чего-то это удобно. И пытаются ловить побочные эффекты таких вот инстациаций, но это все от компилера всё-таки зависит
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Константин Л., Вы писали:
E>>А то я что-то никак не въеду КЛ>и почему id должен быть всегда разным? не очевидно.
ИМХО он никогда не должен. И возникает вопрос о том, может ли?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
R>Comeau online компилит R>К чему я это, я сходу не скажу
Ээээ, я думаю, дело обстоит так. Т.к. f1 у тебя не шаблон, то тут все проще, никаких двухфазных поисков, никаких ПОИ. "Обычный" поиск имен находит функцию с ... . АДЛ ничего не находит (он и не может видеть то, что будет объявлено ниже).
Вызвана будет fun(...). Ну а в main в твоем исходном примере
у тебя уже есть нужное объявление функции друга, обычный поиск имен его не найдет, его найдет ADL.
Of course, the code must be complete enough to compile and link.
Re[9]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>В конце концов на комо никто не работает — все работают на gcc/msvc — а у них такая модель компиляции шаблонов R>Кстати в бусте тоже присутствуют всякие нехорошие моменты и затычки — но они ориентируются именно на работоспособность кода хотя бы под двумя компиляторами — причём зачастую работа под двумя компиляторами достигается по разному
R>
Самое обидное, это когда комо начинает действительно необъяснимо глюкать Такие примеры бывают — вон, недавно что-то спрашивали про sizeof ("такой простой sizeof" или что-то в этом роде, там можно было заметить странное поведение комо)
Of course, the code must be complete enough to compile and link.
Re[12]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>Каким образом там это сломается? У меня ODR нигде не нарушается. Хоть в одну базу их клади, хоть нет, неважно.
E>У тебя-то ODR не нарушается, но вот, если бы компиляторы работали так, как ты хочешь, то легко бы могла нарушаться. E>В этом проблема. E>поэтому работать может как-то неожиданно. Ты же довольно тонкой особенностью реализации пользуешься? E>НУ а попробовать на трансляторе с общей базой шаблонов я тебе посоветовал потому, что там шаблоны оборабатываются сильно не так, как в GCC, например.
Такой трюк может привести к ODR
рассмотрим пример с 3-мя заголовочными файлами
file_01.h:
#pragma once
#include"magic.h"struct some1 : pubilc magic<>
{};
file_02.h:
#pragma once
#include"magic.h"struct some2 : pubilc magic<>
{};
test.h:
#pragma once
#include"magic.h"// включаем только второй файл (1)#include"file_02.h"struct test : pubilc magic<>
{
typedef
some2
type;
type value;
};
test.cpp
#include"test.h"// какой-то код
main.cpp
// включаем и первый файл, потом второй, потом test.h#include"file_01.h"#include"file_02.h"#include"test.h"int main()
{
test t;
return 0;
}
Как видно от порядка включения файлов file_01.h и file_02.h меняется определение класса test
Re[13]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, Sm0ke, Вы писали:
S>Как видно от порядка включения файлов file_01.h и file_02.h меняется определение класса test
1) Конечно может вызвать .
2) Мало ли порядок включения каких хедеров влияет на компиляцию?
Тут будет влиять ещё и порядок инстанцирования шаблонов в единице трансляции.
Скажем так пишем:
void my_processor( ... );
template<class T>
class MyArray : public std::vector<T> {
friend void my_processor( T );
public:
void Process()
{
for( int i = 0; i < size(); i++ )
my_processor( i );
}
};
И теперь код, вызывающий метод MyArray::Process будет зависеть от того, какие именно MyArray<T> уже были инстанциированы к моменту инстанциации вызова этого метода в данной единице трансляции
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[14]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, Erop, Вы писали:
E>Скажем так пишем:
E>void my_processor( ... );
E>template<class T>
E>class MyArray : public std::vector<T> {
E> friend void my_processor( T );
E>public:
E> void Process()
E> {
E> for( int i = 0; i < size(); i++ )
E> my_processor( i );
E> }
E>};
E>И теперь код, вызывающий метод MyArray::Process будет зависеть от того, какие именно MyArray<T> уже были инстанциированы к моменту инстанциации вызова этого метода в данной единице трансляции
было бы интересно глянуть, как ты вызываешь MyArray::Process не инстанцировав MyArray
Re[15]: Невероятно, но факт! Не константные значения в компа
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[16]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, night beast, Вы писали:
NB>>было бы интересно глянуть, как ты вызываешь MyArray::Process не инстанцировав MyArray
E> сравни
а, вот ты о чем
так вроде уж выяснили, что не работает здесь
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, remark, Вы писали:
R>Пришло время очередного ресёрча
Ну... вобщем я так понял, что... код всё-таки противоречит стандарту
Особенное спасибо Lorenzo_LAMAS и Pavel Chikulaev за разъяснения и настойчивость
Ну, лично для меня, это осталось по крайней мере очень интересным и познавательным...
Тем не менее похоже, что не работает это исключительно на Comeau. И это остаётся рабочим вариантом на msvc71/msvc80/gcc34/gcc41/icc70/icc80/edg. Впечатляет, правда? Не работает только на самых свежих фронт-ендах edg.
Имхо список компиляторов достаточен даже для включения в boost
Вообще это очень странно. msvc, gcc и icc имеют разные ядра, и тем не менее модель компиляции таких шаблонов у них поразительно одинаково неправильная
R>
Здравствуйте, remark, Вы писали:
R>Здравствуйте, remark, Вы писали:
R>>Пришло время очередного ресёрча
R>Ну... вобщем я так понял, что... код всё-таки противоречит стандарту R>Особенное спасибо Lorenzo_LAMAS и Pavel Chikulaev за разъяснения и настойчивость
R>Ну, лично для меня, это осталось по крайней мере очень интересным и познавательным...
R>Тем не менее похоже, что не работает это исключительно на Comeau. И это остаётся рабочим вариантом на msvc71/msvc80/gcc34/gcc41/icc70/icc80/edg. Впечатляет, правда? Не работает только на самых свежих фронт-ендах edg.
VC9 Jan CTP. можно тоже включить в список поддерживаемых багофичу
Только бы к релизу не устранили баг
class X;
class Y
{
friend void f(X const &);
};
void g(X const &);
int main()
{
f(getX());
}
Здесь f находится в ::, единственное отличие ее от g — она скрыта от простого поиска. Верно? Но ведь ADL в этом случае рассматривает :: как associated namespace класса X и должна найти функцию!
7.3.1.2/3
Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class or function the friend class or function is a member of the innermost enclosing namespace. The name of the friend is not found by simple name lookup until a matching declaration is provided in that namespace scope (either before or after the class declaration granting friendship). If a friend function is called, its name may be found by the name lookup that considers functions from namespaces and classes associated with the types of the function arguments (3.4.2). When looking for a prior declaration of a class or a function declared as a friend, and when the name of the friend class or function is neither a qualified name nor a template-id, scopes outside the innermost enclosing namespace scope are not considered.
Причем у функции, являющейся другом Y, но не имеющей аргументов типа Y, вполне может быть причина для существования. Например, там внутри Y::instance().somePrivateSubobject().process(x);
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, remark, Вы писали:
R>>
R>>char engine(...);
R>>template<typename, int> struct magic;
R>>typedef magic<char, -1> magicc;
R>>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>>struct magic
R>>{
R>> friend int engine(magicc&, type&);
R>> static const int val = id;
R>>};
R>>int main()
R>>{
R>> char a[magic<>::val != magic<>::val ? 1 : -1];
R>>}
R>>
E>Вот смотри. Я так тебя понял что ты ждёшь, что выделенное неравенство будет соблюдено. E>Вот и поясни (без всяких там ссылок на тонкости стандарта), как, по твоему мнению обстоит дело. E>Где именно и какие именоо инстанциации инстанциируются. То есть укажи пожалуйста место POI для всех участвующих в процессе шаблонов.
E>А то я что-то никак не въеду
все просто.
он не будет всегда разным он будет разным при первом и втором упоминании, в следущих разах будет всегда 4
char engine(...); вот функция которая используется в этом шаблоне. int id = sizeof(engine(*(magicc*)0, *(type*)0)
но как только мы инстанциировали класс magic, то появляется magic — friend int engine(magicc&, type&);
а он как мы видем уже возвращает не char а int (1 vs 4)
и вот во втором включении мы видим уже int engine(magicc&, type&); эту функцию.
для счетчика, где каждый раз обновляется val я написал вот так.
R>>>char engine(...);
R>>>template<typename, int> struct magic;
R>>>typedef magic<char, -1> magicc;
R>>>template<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
R>>>struct magic
R>>>{
R>>> friend int engine(magicc&, type&);
R>>> static const int val = id;
R>>>};
R>>>int main()
R>>>{
R>>> char a[magic<>::val != magic<>::val ? 1 : -1];
R>>>}
R>>>
E>>Вот смотри. Я так тебя понял что ты ждёшь, что выделенное неравенство будет соблюдено. E>>Вот и поясни (без всяких там ссылок на тонкости стандарта), как, по твоему мнению обстоит дело. E>>Где именно и какие именоо инстанциации инстанциируются. То есть укажи пожалуйста место POI для всех участвующих в процессе шаблонов.
IRO>все просто.
Спасибо за разъяснения
К сожалению, ты ответил не на мой вопрос.
Свой вопрпос я выделил полужирным, для удобства.
А замысел ремарка я понял сразу. Только мне кажется, что это всё глюки компилятора
IRO>но как только мы инстанциировали класс magic, то появляется magic — friend int engine(magicc&, type&);
Прекрасно! Где будет POI? Перед функцией main? Или после?
Если перед, то почему не будет действовать на первое же упоминание, если после, то почему будет действовть на второе?..
3E>>А то я что-то никак не въеду
IRO>вот тут!
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: всё ещё прикольнее, чем кажется на первый взгляд!
Здравствуйте, remark, Вы писали:
R>Тем не менее похоже, что не работает это исключительно на Comeau. И это остаётся рабочим вариантом на msvc71/msvc80/gcc34/gcc41/icc70/icc80/edg. Впечатляет, правда? Не работает только на самых свежих фронт-ендах edg. R>Имхо список компиляторов достаточен даже для включения в boost
На самом деле прикольно, что глюк совпадает. Я бы озаботился вопросом о переиспользовании чужого кода...
Чтобы было понятнее о чём таки я, надо попробовать объяснить как же всё-таки работает компилятор?
Чтобы было легче, надо ответить на уточнённый вспомогательный вопрос
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: всё ещё прикольнее, чем кажется на первый взгляд!
Уж не намекаете ли ва на то, что злые коммерческие дядьки из Microsoft и Intel использовали(читай спиз$или) беззащитный, открытый GPL-ый(?) код синтаксического анализа gcc? И теперь цинично делают деньги? Как такое можно подумать.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[4]: всё ещё прикольнее, чем кажется на первый взгляд!
Здравствуйте, Ka3a4oK, Вы писали:
KK>Уж не намекаете ли ва на то, что злые коммерческие дядьки из Microsoft и Intel использовали(читай спиз$или) беззащитный, открытый GPL-ый(?) код синтаксического анализа gcc? И теперь цинично делают деньги? Как такое можно подумать.
Я намекаю на то, что не совсем понятно как хитро так работают инстанциаторы шаблонов в разных компиляторах.
Наверняка авторы разных компиляторов не только решали схожие задачи и читали схожиекниги, но и смтрели на изделия конкурентов. И то, что глюк столь распрорстранён наверняка имеет какую-то пичину. Если это не банальный цельнотянутый код (я в это не верю, так как даже если код тянут, то его ремасерят, особенно, если он живёт много версий и поддерживается и развивается), то навкрняка есть какая-то довольно глубокая и нетривиальная причина...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Невероятно, но факт! Не константные значения в компайл-т
namespace compile_time_flag
{
struct yes{};
struct no{char _no[2];};
no check(...);
template <class,class,int> struct flag;
template <class T> T& make_ref();
template <class flag_type,class type = yes, int id = sizeof(check(make_ref<flag<flag_type,no,-1> >(), make_ref<type>()))==sizeof(yes)>
struct flag
{
friend yes check(flag<flag_type,no,-1>&,type&);
static const int IsTrue = id;
};
}
#include <iostream>
int main()
{
char a[compile_time_flag::flag<int>::IsTrue != compile_time_flag::flag<int>::IsTrue ? 1 : -1];//Первый 0, второй 1static const int i = compile_time_flag::flag<char>::IsTrue;//0static const int j = compile_time_flag::flag<double>::IsTrue;//0static const int k = compile_time_flag::flag<double>::IsTrue;//1static const int l = compile_time_flag::flag<char>::IsTrue;//1static const int m = compile_time_flag::flag<char>::IsTrue;//1
std::cout<<i<<j<<k<<l<<m;//00111
}
Все работает на 8.0 студии именно так, как мне хочется. Естественно, захотелось, чтобы и под другими компиляторами работало. remark обещает работоспособность под кучей компиляторов, кроме Comeau. Пытался найти объяснение. Находил нечто похожее, например здесь
для Comeau Online оба значения равны 0! Что означает, что при вычислении default параметра id всегда используется функция с эллипсисом. Несмотря на то, что ADL должен найти friend функцию(хотя бы в одном месте).
Итак, объясните мне, почему Comeau работает так(желательно с указанием стандарта), или относим Comeau к не поддерживающим стандарт компиляторам и еще раз апплодируем идее
Ну, и как оно должно все-таки работать, желательно — список действий компилятора.
Всем заранее спасибо
<вырезано, дабы сохранить место на сервере>
Re[2]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, tilarids, Вы писали:
T>для Comeau Online оба значения равны 0! Что означает, что при вычислении default параметра id всегда используется функция с эллипсисом. Несмотря на то, что ADL должен найти friend функцию(хотя бы в одном месте).
T>Итак, объясните мне, почему Comeau работает так(желательно с указанием стандарта), или относим Comeau к не поддерживающим стандарт компиляторам и еще раз апплодируем идее T>Ну, и как оно должно все-таки работать, желательно — список действий компилятора.
Comeau судя по всему как раз единственный делает правильно. А все остальные компиляторы очень подозрительно делают одну и ту же ошибку. Хотя вопрос очень тёмный и с уверенностью здесь сказать что-либо сложно.
Как это должно работать (как делает Comeau).
Если функция может быть найдена с помощью обычного поиска или ADL, то она должна быть найдена в любом случае. Результат поиска не должен завистеть ни от чего, в том числе от того какие шаблоны были инстанциированы до этой точки.
Как делают все остальные.
Функция находится с помощью ADL только после того, как шаблон её содержащий был инстанциирован.
Т.е. компилятор должен в данном случае при осуществлении ADL инстанциировать все классы, которые относятся к типу каждого параметра функции и посмотреть, не появилось ли новой подходящей функции во время этого инстанциирования. Как-то так.
Здравствуйте, remark, Вы писали:
R>Comeau судя по всему как раз единственный делает правильно. А все остальные компиляторы очень подозрительно делают одну и ту же ошибку. Хотя вопрос очень тёмный и с уверенностью здесь сказать что-либо сложно.
R>Как это должно работать (как делает Comeau). R>Если функция может быть найдена с помощью обычного поиска или ADL, то она должна быть найдена в любом случае. Результат поиска не должен завистеть ни от чего, в том числе от того какие шаблоны были инстанциированы до этой точки.
R>Как делают все остальные. R>Функция находится с помощью ADL только после того, как шаблон её содержащий был инстанциирован.
R>Т.е. компилятор должен в данном случае при осуществлении ADL инстанциировать все классы, которые относятся к типу каждого параметра функции и посмотреть, не появилось ли новой подходящей функции во время этого инстанциирования. Как-то так.
R>
Comeau Online демонстрирует вообще замечательное поведение — там просто ADL не работает. То бишь:
namespace compile_time_flag
{
struct yes{};
struct no{char _no[2];};
no check(...);
template <class,class,int> struct flag;
template <class T> T& make_ref();
template <class flag_type,class type = yes, int id = sizeof(check(make_ref<flag<flag_type,no,-1> >(), make_ref<type>()))==sizeof(yes)>
struct flag
{
friend yes check(flag<flag_type,no,-1>&,type&);
static const int IsTrue = id;
};
}
#include <iostream>
int main()
{
char a[compile_time_flag::flag<int>::IsTrue ==0 ? 1 : -1];
char b[compile_time_flag::flag<int>::IsTrue ==0 ? 1 : -1];
(void)a;
(void)b;
}
Выдает только 1 warning о нетемплейтовой friend функции — все прекрасно компилится. Хотя ADL должен приводить к тому, что будет найдена
friend yes check(flag<flag_type,no,-1>&,type&);
А находит функцию с эллипсисом.
Так что я, наверное, все же реализую подобный подход Вот только скорее не отсюда, а с boost lists
<вырезано, дабы сохранить место на сервере>
Re: Невероятно, но факт! Не константные значения в компайл-т
Здравствуйте, tilarids, Вы писали:
T>Comeau Online демонстрирует вообще замечательное поведение — там просто ADL не работает.
LROTF
Ты тут просто неправильно написал. Ты не ту функцию другом объявляешь или точнее другом не того класса.
Хинт: тип flag<no> и тип flag<yes> — совершенно разные типы. При ADL поиске через один тип не будут находится функции связанные с другим типом.
Если не изменяет память, в этом топике я приводил решение для этой проблемы.
Здравствуйте, Yoh Asakura, Вы писали:
YA>Все что невероятно — заканчивается обычно тем, что сия магия перестает работать на выпущенных позже компиляторах.
Сия магия заканчивается обычно тем, что производителям компиляторов приходится пожизненно поддерживать флаги для обратной совместимости поведения. Даже если это было не стандартное поведение или просто баг.
Здравствуйте, Yoh Asakura, Вы писали:
YA>Не согласен, ибо тон задают создатели стандарта и производители компилятора, а все остальные вынуждены писать в своем коде обходные макросы =)
Какие есть примеры, когда производитель массового продукта не обратно совместимо менял поведение и рушил тем самым клиентский код?
Производители массового продукта подобные вещи наружу не выносят, а отдают откомпелированный код.
А за примерами идти надо в OpenSource — так он наполнен подобным, когда изменение в GCC по исправлению баги приводит к тому, что даже известные OpenSource библиотеки не собираются, не говоря уже попытке собрать старую версию ядра новым компилятором...
Здравствуйте, tilarids, Вы писали:
T>Итак, объясните мне, почему Comeau работает так(желательно с указанием стандарта), или относим Comeau к не поддерживающим стандарт компиляторам и еще раз апплодируем идее T>Ну, и как оно должно все-таки работать, желательно — список действий компилятора. T>Всем заранее спасибо
ИМХО этот код работать не должен. Это если по стандарту.
Чтобы убедить меня в обратном, укажи пожалуйста в каких именно местах единицы трансляции должны находиться POI каких именно шаблонов,
чтобы в этой строчке
"compile_time_flag::flag<int>::IsTrue" компилировалось по разному слева и справа от оператора !=.
То что на остальных компиляторах этот хак работает не о чём, кроме неаккуратного использования в этих компиляторах статических переменных не говорит
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>Сия магия заканчивается обычно тем, что производителям компиляторов приходится пожизненно поддерживать флаги для обратной совместимости поведения. Даже если это было не стандартное поведение или просто баг.
R>
Не, ну это ты себе льстишь всё-таки. Хотя хак классный, жалко, что не по стандарту
Для того, чтобы производители компилятора поддерживали в следующих версиях багу, как фичу, требуется, чтобы багу начали использовать таки массово
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>Какие есть примеры, когда производитель массового продукта не обратно совместимо менял поведение и рушил тем самым клиентский код?
Фирму Microsoft знаешь?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, Erop, Вы писали:
E>Не, ну это ты себе льстишь всё-таки. Хотя хак классный, жалко, что не по стандарту E>Для того, чтобы производители компилятора поддерживали в следующих версиях багу, как фичу, требуется, чтобы багу начали использовать таки массово
Ну есть немного
А для того, что бы багу исправили в следующей версии компилятора тоже требуется, что бы багу "начали использовать массово". Т.ч. я всё равно не думаю, что М$ будет париться и исправлять *такой* баг, мне даже его субмитить лень.
Вот я один им отправлял здесь, так они ответили:
[бла-бла-бла, мы не будем исправлять баг, т.к] as the code is convoluted and does not reflect the majority of real world use cases
Здравствуйте, remark, Вы писали:
R>Здравствуйте, tilarids, Вы писали:
T>>Comeau Online демонстрирует вообще замечательное поведение — там просто ADL не работает.
R>LROTF
R>Ты тут просто неправильно написал. Ты не ту функцию другом объявляешь или точнее другом не того класса. R>Хинт: тип flag<no> и тип flag<yes> — совершенно разные типы. При ADL поиске через один тип не будут находится функции связанные с другим типом. R>Если не изменяет память, в этом топике я приводил решение для этой проблемы.
R>
Так. Сейчас будем очень аккуратно разбираться. Дело в том, что это твой же пример — я просто его чуть-чуть переделал. И поверил тебе, что там ADL. Могу даже на твоем же коде продемонстрировать.
char engine(...);//Всего одна функцияtemplate<typename, int> struct magic;
typedef magic<char, -1> magicc;//При typedef ничего не инстанцируется - все еще одна функцияtemplate<typename type = int, int id = sizeof(engine(*(magicc*)0, *(type*)0))>
//magicc снова не инстанцируется - это не нужно
//то есть, в magicc:: нет friend int engine(magicc&, type&);
//получается id = sizeof возвращаемого значения первой функции(с эллипсисом)struct magic
{
friend int engine(magicc&, type&);//появляется magic<int,sizeof(char)>::engine(magicc&, type&)
//При следуюущем вызове ADL действительно работать не будет, ведь ADL по magicc - ничего не найдет, ибо magicc не инстанцируется никогда.static const int val = id;
};
int main()
{
char a[magic<>::val != magic<>::val ? 1 : -1];//Почему же тогда это работает в стольких компиляторах????
}
По поводу моего примера — я бы не присылал его, если бы не проверил — он работает также, как и твой. Во всех компайлерах, мне доступных.
Comeau действительно отрабатывает правильно. Потому что нет ADL. Я решил туда его добавить — для этого нужно просто инстанцировать класс, который передается параметром в функцию ПОСЛЕ первого вызова этой функции. Сделал вот такую вещь:
struct yes{};
struct no{char _no[2];};
no check(...);
template <class,class,int> struct flag;
template <class T> T& make_ref();
template <class T> T* make_ptr();
template <typename T> yes is_same_tester(T*, T*);
no is_same_tester(...);
template< class T1, class T2 >
struct is_same//Проверка типов на равенство
{
enum { value = sizeof(is_same_tester(make_ptr<T1>(),make_ptr<T2>()))==sizeof(yes)};
};
template <int val,class true_class,class false_class>
struct typeselector;//Выбирает тип в зависимости от значения valtemplate <class true_class,class false_class>
struct typeselector<0,true_class,false_class>
{
typedef false_class type;//если 0 - то здесь - false_class
};
template <class true_class,class false_class>
struct typeselector<1,true_class,false_class>
{
typedef true_class type; //если 1 - то здесь - true_class
};
class Dummy//пустой класс, нужен для наследования
{
};
template <class flag_type,class type = yes, int id = sizeof(check(make_ref<flag<flag_type,no,-1> >(), make_ref<type>()))==sizeof(yes)>
struct flag : public typeselector<is_same<flag<flag_type,type,id>,flag<flag_type,no,-1> >::value,Dummy,flag<flag_type,no,-1> >::type
//Вся идея заключается в применении наследования для форсирования инстанцирования нужного нам класса. Так как оно должно обрабатываться после подсчёта default параметров, то мы все так же получаем 0 при первом инстанцировании.
//Так как наследоваться от самого себя нельзя, то делаем проверку типов, и в случае инстанцирования flag<flag_type,no,-1> наследуемся от Dummy
{
friend yes check(flag<flag_type,no,-1>&,type&);
static const int IsTrue = id;
};
char a[flag<int>::IsTrue == 0 ? 1 : -1];//0char b[flag<int>::IsTrue == 1 ? 1 : -1];//1 - вот здесь комо валится
//Все прекрасно работает на студии, но все так же не работает на Comeau
Извиняюсь за корявость примера, возможно там где-то ошибки внутри кода. Если кто сможет написать, чтобы работало ADL без всяких лишних телодвижений(элементарная подстановка в расчёте id другого имени класса почему-то приводит к тому, что все перестает работать) — просим. Кто сможет объяснить — в чем я не прав, или, в другом случае, привести более короткий и красивый пример — буду рад.
PS. Кстати, комо инстанцирует шаблоны в моем случае именно в таком порядке:
1. flag<int,yes,0>
2. flag<int,no,-1>//Первые два определил по сообщениям об ошибках
3. Не инстанцируется flag<int,yes,1>
<вырезано, дабы сохранить место на сервере>
Re[6]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, tilarids, Вы писали:
T> char a[magic<>::val != magic<>::val ? 1 : -1];//Почему же тогда это работает в стольких компиляторах????
Потому что на них на всех ещё одна бага, они считают, что flag<yes> и flag<no> один тип в плане ADL и друзей.
T>char b[flag<int>::IsTrue == 1 ? 1 : -1];//1 — вот здесь комо валится
Всё правильно валится, он то как раз по стандарту всё делает.
Здравствуйте, Erop, Вы писали:
E>ИМХО этот код работать не должен. Это если по стандарту.
E>Чтобы убедить меня в обратном, укажи пожалуйста в каких именно местах единицы трансляции должны находиться POI каких именно шаблонов, E>чтобы в этой строчке
"compile_time_flag::flag<int>::IsTrue" компилировалось по разному слева и справа от оператора !=.
E>То что на остальных компиляторах этот хак работает не о чём, кроме неаккуратного использования в этих компиляторах статических переменных не говорит
Я тоже согласен, что код работать никак не должен. Ибо результат не должен зависеть от порядка инстанцирования шаблонов. Я хочу сделать нечто другое: некое подобие init. То бишь, меня не волнует, в каком порядке инстанцировались шаблоны. Мне хочется, чтобы если где-нибудь, или когда-нибудь участвовал некий специально сформированный шаблон, то автоматически где-нибудь некая сущность это в себе хранила. Что-то вроде:
//идеальный вариант
work_if<verifier<type>::inited,Dummy,Worker>().Work();//Использует класс в зависимости от значения
init<type>::init;//Если оно здесь есть, то verifier<type>::inited везде становится равным 1, иначе - 0
work_if<verifier<type>::inited,Dummy,Worker>().Work();//Использует класс в зависимости от значения
work_if<verifier<type>::inited,Dummy,Worker>().Work();//Использует класс в зависимости от значения
//удовлетворюсь таким - раз уж столько компиляторов подряд инстанцируют
//его уже можно реализовать - могу кинуть код - жаль, не свой.
init<type>::init;//Если оно здесь есть, то verifier<type>::inited везде становится равным 1, иначе - 0
work_if<verifier<type>::inited,Dummy,Worker>().Work();//Использует класс в зависимости от значения
work_if<verifier<type>::inited,Dummy,Worker>().Work();//Использует класс в зависимости от значения
work_if<verifier<type>::inited,Dummy,Worker>().Work();//Использует класс в зависимости от значения
PS. Пока писал — появились идеи
<вырезано, дабы сохранить место на сервере>
Re[7]: Невероятно, но факт! Не константные значения в компай
Здравствуйте, remark, Вы писали:
R>Здравствуйте, tilarids, Вы писали:
T>> char a[magic<>::val != magic<>::val ? 1 : -1];//Почему же тогда это работает в стольких компиляторах????
R>Потому что на них на всех ещё одна бага, они считают, что flag<yes> и flag<no> один тип в плане ADL и друзей.
T>>char b[flag<int>::IsTrue == 1 ? 1 : -1];//1 — вот здесь комо валится
R>Всё правильно валится, он то как раз по стандарту всё делает.
R>
Дело в том, что раз Comeau работает по стандарту, значит, он должен найти
T>>Он там точно есть. Если ADL не должен находить его — то что же вообще он должен находить? Это ведь именно тот же самый тип!
R>Да, должен найти, только в обеих случаях, а не только во втором.
Ну, это стандартом не оговорено, кажется, — что должно происходить вначале — подсчёт дефолтовых параметров, или включение в loookup всех внутренних функций. Если оговорено — цитату, пожалуйста. А то Comeau пока в меньшинстве — мне более логичным на моем примере кажется поведение именно всех остальных компиляторов(точнее, поведение на нем студии )
T>...Мне хочется, чтобы если где-нибудь, или когда-нибудь участвовал некий специально сформированный шаблон, то автоматически где-нибудь некая сущность это в себе хранила. Что-то вроде:
Ну для этого ADL вроде как подходит...
Хотя всё равно только в пределах единицы трансляции. А что будет с базой шаблонов --
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, tilarids, Вы писали:
T>>...Мне хочется, чтобы если где-нибудь, или когда-нибудь участвовал некий специально сформированный шаблон, то автоматически где-нибудь некая сущность это в себе хранила. Что-то вроде:
E>Ну для этого ADL вроде как подходит...
E>Хотя всё равно только в пределах единицы трансляции. А что будет с базой шаблонов --
Переписал все заново — теперь все выглядит намного проще. Чистый код:
int main()
{
using namespace compile_time_flag;
static const int j = CHECK(int);
INIT (int);
static const int i = CHECK(int);
char b[i!=j?1:-1];
(void)b;
return 0;
}
Some more files:
"RealWorker.h"
#pragma once
#include <iostream>
class CRealWorker
{
public:
CRealWorker(void);
~CRealWorker(void);
void Work()
{
std::cout<<"Real work goes here!!!\n";
}
};
"DummyWorker.h"
#pragma once
#include <iostream>
class CDummyWorker
{
public:
CDummyWorker(void);
~CDummyWorker(void);
void Work()
{
std::cout<<"Just relaxing :)\n";
}
};
"Worker1.h"
#pragma once
#include"DummyWorker.h"#include"RealWorker.h"#include"compile_time_flag.h"template <int value>
class CWorker1;
template <>
class CWorker1<0> : public CDummyWorker
{
};
template <>
class CWorker1<1> : public CRealWorker
{
};
struct Worker{};
#define CWorker CWorker1< CHECK(Worker) >
#define InitWorker() INIT(Worker)
Usage:
int main()
{
using namespace compile_time_flag;
CWorker w1;
InitWorker();
CWorker w2;
w1.Work();//dummy
w2.Work();//workreturn 0;
}
Как видно, использовать можно как и в простых случаях, так и в более сложных структурах. Естественно, с большой уверенностью, что именно ты делаешь
И самое приятное. Компилируется и работает в VC8, а также в Comeau Online и здесь в MINGW/C++ и EDG/C++.
PS. Проверял только Simple usage в онлайн компайлерах, по причинам вполне понятным
T>int main()
T>{
T> using namespace compile_time_flag;
T> static const int j = CHECK(int);
T> INIT (int);
T> static const int i = CHECK(int);
T> char b[i!=j?1:-1];
T> (void)b;
T> return 0;
T>}
T>
Двухфазный механизм возможно дает тоже. Не сообрауже сразу чем бинарный CHECK INIT может быть лучше.
Можно еще очистить этот код, чтоб вообще никакой магии не было
T>int main()
T>{
T> using namespace compile_time_flag;
T> static const int j = CHECK(int);
T> INIT (int);
T> static const int i = CHECK(int);
T> char b[i!=j?1:-1];
T> (void)b;
T> return 0;
T>}
T>
Ну типа A<int> -- локальный класс?
По идее, если по стандарту, то POI A<int> должно бы быть до функции main, так как A<int> вроде как с внешним связыванием...
T>PS. Проверял только Simple usage в онлайн компайлерах, по причинам вполне понятным
ИМХО в любой момент могёт рвануть....
Ну и главное, можно проще намного сделать.
Типа так:
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[10]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, tilarids, Вы писали:
T>Ну, это стандартом не оговорено, кажется, — что должно происходить вначале — подсчёт дефолтовых параметров, или включение в loookup всех внутренних функций. Если оговорено — цитату, пожалуйста. А то Comeau пока в меньшинстве — мне более логичным на моем примере кажется поведение именно всех остальных компиляторов(точнее, поведение на нем студии )
Согласен — нормальное поведение компиляторов. Все компилирую. Правда VC6 захотел имена в предварительной декларации и енум вместо статик. А Comeau известен своей глючностью
int main()
{
compile_time_flag::flag<float> f0a,f0b;
compile_time_flag::flag<float> f1a,f1b;
int idv[]={f0b.IsTrue,f1b.IsTrue}; // разные значения
f0a=f0b;
f1a=f1b;
f0a=f1a; // присваивание невозможно - ошибка
}
В С полно таких мест когда один и тоже код ведет себя по разному в различных местах. А заставлять компилятор лазить внутрь — это превращать его в пролог Поведение компилятора должно быть как можно проще, тогда все предсказуемо будет
Re[10]: Невероятно, но факт! Не константные значения в компа
Здравствуйте, tilarids, Вы писали:
R>>Да, должен найти, только в обеих случаях, а не только во втором.
T>Ну, это стандартом не оговорено, кажется, — что должно происходить вначале — подсчёт дефолтовых параметров, или включение в loookup всех внутренних функций. Если оговорено — цитату, пожалуйста. А то Comeau пока в меньшинстве — мне более логичным на моем примере кажется поведение именно всех остальных компиляторов(точнее, поведение на нем студии )
Тут дело не в том, что раньше: подсчёт дефолтовых параметров, или включение в loookup всех внутренних функций.
Тут всё проше — если функция может быть найдена, то она должна быть найдена.
Ссылку из стандарта ISO привести сложно, т.к. это базовая вещь. Нет какого-то одного абзаца, который конкретно разъяснял всю эту ситуацию. Тут смешано очень много вещей.
Общая идея такая. (Это как раз, то что я пытался опровергнуть, но не получилось. Ну точнее не получилось в соотв. со стандартом ISO, а на большинстве компиляторов как-раз получилось).
У компилятора в процессе компиляции нет контекста (т.е. состояния). Точнее нет изменяемого контекста (т.е. того, на которой может влиять программист). Т.е. у компилятора в каждой точке программы есть один чётко определённый контекст. Соответственно отсюда следует, что в принципе не может быть ничего о чём я писал — главное — не может быть "переменных", т.е. одно и тоже выражение в одном и том же контексте (читай — месте программы) не может иметь разных значений. И в этом принципиальное отличие от "ран-тайм".
Здравствуйте, remark, Вы писали:
R>Здравствуйте, tilarids, Вы писали:
T>>И самое приятное. Компилируется и работает в VC8, а также в Comeau Online
R>Ты попробуй Comeau Online не с dinkumware, а который они сами предлагают. На dinkumware старая версия, а они похоже это исправляли как раз недавно.
R>
Проверял здесь . Кажется, официальный вариант Если же имеется ввиду оффлайн компайлер+линкер — то на него я денег не имею
В общем, нити, повторное обсуждение в которых я спровоцировал , можно считать закрытыми. Действительно, такой трюк скорее восстает не против стандарта, а против здравого смысла. Кроме того, для себя я понял, что Comeau не так хорош в поддержке стандарта, как его рисуют(как, в принципе и остальные компиляторы — но это не мешает им работать).
Теперь осталось найти язык, сходный с С++ по системным возможностям(а лучше — позволяющий использовать С++ конструкции в каком-либо удобном виде).
Здравствуйте, tilarids, Вы писали:
T>Проверял здесь . Кажется, официальный вариант Если же имеется ввиду оффлайн компайлер+линкер — то на него я денег не имею
Ну так и чего на нём? Работает или нет? В смысле, наверное правильнее спрашивать, как работает?
T>В общем, нити, повторное обсуждение в которых я спровоцировал , можно считать закрытыми. Действительно, такой трюк скорее восстает не против стандарта, а против здравого смысла. Кроме того, для себя я понял, что Comeau не так хорош в поддержке стандарта, как его рисуют(как, в принципе и остальные компиляторы — но это не мешает им работать).
А чем Comeau не соотв. стандарту? Как раз вроде он один и соотв.
T>Теперь осталось найти язык, сходный с С++ по системным возможностям(а лучше — позволяющий использовать С++ конструкции в каком-либо удобном виде).
Здравствуйте, tilarids, Вы писали:
T>...такой трюк скорее восстает не против стандарта, а против здравого смысла.
Ну связь здравого смысла и стандарта С++ темна для меня. Но мне таки кажется, что такой трюк не должен работать именно по стандарту. Или укажи таки POI задействованных шаблонов
И главное, чем тебе просто объявлять функцию какого-то прототипа, в макросе INIT не нравится? Всё по стандарту, без хаков и надёжно вроде...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, remark, Вы писали:
R>Здравствуйте, tilarids, Вы писали:
T>>Проверял здесь . Кажется, официальный вариант Если же имеется ввиду оффлайн компайлер+линкер — то на него я денег не имею
R>Ну так и чего на нём? Работает или нет? В смысле, наверное правильнее спрашивать, как работает?
Интересно как именно он работает
namespace compile_time_flag
{
struct yes{};
struct no{char _no[2];};
no check(...);
template <class,class,int> struct flag;
template <class T> T& make_ref();
template <class flag_type,class type = yes
, int id = sizeof(check(make_ref<flag<flag_type,no,-1> >(), make_ref<type>()))==sizeof(yes)>
struct flag
{ friend yes check(flag<flag_type,no,-1>&,type&);
enum { IsTrue = id};
};
}
int main()
{
compile_time_flag::flag<float> f0a,f0b;
compile_time_flag::flag<float> f1a,f1b;
int idv[]={f0b.IsTrue,f1b.IsTrue}; // разные значения
f0a=f0b;
f1a=f1b;
f0a=f1a; //присваивание разных инстанций - ошибка в VC8 ok Comeau
}
У VC8 первая переменная типа <.., no, 0> вторая типа <.., no, 1> у Comeau одног. Интересно какого?
namespace compile_time_flag
{
struct yes{} dyes;
struct no{char _no[2];};
no check(...);
template <class,class,int> struct flag;
template <class T> T& make_ref();
template <class flag_type,class type = yes, int id = sizeof(check(make_ref<flag<flag_type,no,-1> >(), make_ref<type>()))==sizeof(yes)>
struct flag
{ friend yes check(flag<flag_type,no,-1>&,type&);
// отсюда начинается видимость yes checkenum { IsTrue = id};
};
// yes check(flag<float,no,-1>&,yes&);
// это таки ломает его
}
using namespace compile_time_flag;
int main()
{ compile_time_flag::flag<float,compile_time_flag::yes,0> d0;
compile_time_flag::flag<float,compile_time_flag::no,-1> f0;
yes yy=check(f0,dyes);
// здесь yes check точно видна во время исполнения
compile_time_flag::flag<float> f0a,f0b;
compile_time_flag::flag<float> f1a,f1b;
int idv[]={f0b.IsTrue,f1b.IsTrue};
f0a=f0b;
f1a=f1b;
d0=f0a; // проверяем что f0a типа compile_time_flag::flag<float,compile_time_flag::yes,0>
// поскольку 0 yes check() не учлась в шаблон, тоесть не видна
f0a=f1a; // второй compile_time_flag::flag<float> тотже, тоесть с 0
}
namespace compile_time_flag
{ // сама функция
yes check(flag<float,no,-1>&,yes&)
{ return dyes;
}
}
Получаетс следующая картина деклараци френд делает функцию доступной для непосредственного вызова, но недоступной для шаблонов. Явное противоречие.
Комеау опять не со всеми, правда обычно он отказывается когда должен,
сейчас скомпилил когда не должен
void f(int);
f(1.);
void f(double);
f(1.);
Такой код никого не удивляет. Здесь аналогично. compile_time_flag::flag<float> должны быть 2 разных класса