VC и GCC: разное поведение, а как д.б. по стандарту?
От: stil.man  
Дата: 27.03.12 11:25
Оценка: :)
Я так понимаю особенность известная, но я хотел бы кое что для себя прояснить.

Есть элементарный код, который при компиляции в VC и в GCC дает разный результат:


#include <iostream>
#include <stdio.h>

void foo()
{
    std::cout << "\r\nGlobal\r\n";
}


template <typename T> class Base {
public:
    void foo()
    {
        std::cout << "\r\nBase\r\n";    }
};

template <typename T> class Derived : public Base<T> {
public:
    int call_foo ()  {
        foo();
        return 1;
    }
};


int main(int argc, char* argv[])
{
    //foo = 666;

    Derived<int> h;
    h.call_foo();

    //std::cout << h.get_foo() << std::endl;
    return 0;
}



VC(2008 и старшие): 
Base
GCC(4.6.1):
Global


Я не хочу вдаваться в такие вещи как "two-phase name lookup" или ADL, потому что все таки это особенности реализации компиляторов, и в стандарте о них нет ни слова.
Я хочу понять, какое поведение как правильное определяется стандартом ?
И как с этим вообще жить ? Почему так ?:)
Re: VC и GCC: разное поведение, а как д.б. по стандарту?
От: uzhas Ниоткуда  
Дата: 27.03.12 11:37
Оценка:
Здравствуйте, stil.man, Вы писали:

SM>Я не хочу вдаваться в такие вещи как "two-phase name lookup" или ADL, потому что все таки это особенности реализации компиляторов, и в стандарте о них нет ни слова.

ADL вполне себе стандартизованная вещь, хотя не имеет отношения к данной проблеме

SM>Я хочу понять, какое поведение как правильное определяется стандартом ?

не могу сказать точно, но интуитивном уровне подоpреваю баг у гцц.
гцц славится своей способностью "компилировать" шаблоны (то есть как-то их препроцессить еще до фазы инстанциирования). на этой фазе базовый класс неизвестен и гцц неверно подставляет вызов функии foo

SM>И как с этим вообще жить ? Почему так ?

более явно можно прописывать, что за функцию мы вызываем
::foo(); // вызываем глобальную функцию
this->foo(); // вызываем свою


успехов
Re: VC и GCC: разное поведение, а как д.б. по стандарту?
От: wander  
Дата: 27.03.12 11:37
Оценка: +1
Здравствуйте, stil.man, Вы писали:

this->foo сделать. Почему так — в поиск по рсдн, тут уже было как минимум два эпических **ча на эту тему.
avalon 1.0rc3 build 426, zlib 1.2.3
Re: VC и GCC: разное поведение, а как д.б. по стандарту?
От: Lucky Cat  
Дата: 27.03.12 11:46
Оценка:
Здравствуйте, stil.man, Вы писали:

SM>VC(2008 и старшие):

SM>Base
SM>GCC(4.6.1):
SM>Global
SM>[/code]

SM>Я не хочу вдаваться в такие вещи как "two-phase name lookup" или ADL, потому что все таки это особенности реализации компиляторов, и в стандарте о них нет ни слова.

SM>Я хочу понять, какое поведение как правильное определяется стандартом ?
SM>И как с этим вообще жить ? Почему так ?


GCC (4.7.0) error required from here в строке 31:Derived<int> h;

Re[2]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: stil.man  
Дата: 27.03.12 12:00
Оценка:
Здравствуйте, wander, Вы писали:

W>Здравствуйте, stil.man, Вы писали:


this->>foo сделать. Почему так — в поиск по рсдн, тут уже было как минимум два эпических **ча на эту тему.

То что были срачи не очевидно, а поиск как по вашему ключевому слову так и по другим не помог, вылетает куча всего но не то что нужно.
Можете дать конкретную ссылку если хотите.
Re[2]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: stil.man  
Дата: 27.03.12 12:03
Оценка:
Здравствуйте, Lucky Cat, Вы писали:

LC>Здравствуйте, stil.man, Вы писали:




LC>

LC>GCC (4.7.0) error required from here в строке 31:Derived<int> h;

LC>

Чё это он ?.... странна. Все же валидно.
Re: VC и GCC: разное поведение, а как д.б. по стандарту?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 27.03.12 12:06
Оценка:
Здравствуйте, stil.man, Вы писали:

SM>Я так понимаю особенность известная, но я хотел бы кое что для себя прояснить.


Заккоментируйте void foo(), потом гуглите по диагностическому сообщению от GCC.
Re[3]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: Lucky Cat  
Дата: 27.03.12 12:06
Оценка:
Здравствуйте, stil.man, Вы писали:

LC>>

LC>>GCC (4.7.0) error required from here в строке 31:Derived<int> h;

LC>>

SM>Чё это он ?.... странна. Все же валидно.

Непанятна. Еще дома в Линуксе попробую, это я мингв-гцц 4.7.0 пользовал.
Re[2]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: Masterkent  
Дата: 27.03.12 12:10
Оценка: 3 (1)
uzhas:

SM>>Я не хочу вдаваться в такие вещи как "two-phase name lookup" или ADL, потому что все таки это особенности реализации компиляторов, и в стандарте о них нет ни слова.

U>ADL вполне себе стандартизованная вещь

Как и two-phase name lookup.

SM>>Я хочу понять, какое поведение как правильное определяется стандартом ?

U>не могу сказать точно, но интуитивном уровне подоpреваю баг у гцц.

GCC поступает правильно (см. 14.6.2/3)

SM>>И как с этим вообще жить ? Почему так ?

U>более явно можно прописывать, что за функцию мы вызываем
U>
U>this->foo(); // вызываем свою

Ещё можно использовать using

struct B
{
    void f() {}
};

template <class T>
    struct D : T
{
    using T::f;

    void g()
    {
        f();
    }
};

int main()
{
    D<B>().g();
}
Re[2]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: samius Япония http://sams-tricks.blogspot.com
Дата: 27.03.12 12:11
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, stil.man, Вы писали:


SM>>Я так понимаю особенность известная, но я хотел бы кое что для себя прояснить.


S>Заккоментируйте void foo(), потом гуглите по диагностическому сообщению от GCC.


Вот, кстати
http://gcc.gnu.org/onlinedocs/gcc/Name-lookup.html
Re: VC и GCC: разное поведение, а как д.б. по стандарту?
От: Сыроежка  
Дата: 27.03.12 12:19
Оценка: 1 (1) +1
Здравствуйте, stil.man, Вы писали:

SM>Я так понимаю особенность известная, но я хотел бы кое что для себя прояснить.


SM>Есть элементарный код, который при компиляции в VC и в GCC дает разный результат:


SM>

SM>#include <iostream>
SM>#include <stdio.h>

SM>void foo()
SM>{
SM>    std::cout << "\r\nGlobal\r\n";
SM>}


SM>template <typename T> class Base {
SM>public:
SM>    void foo()
SM>    {
SM>        std::cout << "\r\nBase\r\n";    }
SM>};

SM>template <typename T> class Derived : public Base<T> {
SM>public:
SM>    int call_foo ()  {
SM>        foo();
SM>        return 1;
SM>    }
SM>};


SM>int main(int argc, char* argv[])
SM>{
SM>    //foo = 666;

SM>    Derived<int> h;
SM>    h.call_foo();

SM>    //std::cout << h.get_foo() << std::endl;
SM>    return 0;
SM>}
SM>



SM>
SM>VC(2008 и старшие): 
SM>Base
SM>GCC(4.6.1):
SM>Global
SM>


SM>Я не хочу вдаваться в такие вещи как "two-phase name lookup" или ADL, потому что все таки это особенности реализации компиляторов, и в стандарте о них нет ни слова.

SM>Я хочу понять, какое поведение как правильное определяется стандартом ?
SM>И как с этим вообще жить ? Почему так ?

Мне представляется, что смотреть раздел стандарта 14.6 Name resolution. В параграфе №10 говорится следующее:

10 If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations)
for that name shall be in scope at the point where the name appears in the template definition; the name is
bound to the declaration (or declarations) found at that point and this binding is not affected by declarations
that are visible at the point of instantiation. [ Example:

void f(char);
template<class T> void g(T t) {
f(1); // f(char)
f(T(1)); // dependent
f(t); // dependent
dd++; // not dependent
// error: declaration for dd not found
}
enum E { e };
void f(E);
double dd;
void h() {
g(e); // will cause one call of f(char) followed
// by two calls of f(E)
g(’a’); // will cause three calls of f(char)
}
—end example

Поэтому, если я корректно сослался на нужный раздел, именно GCC ведет себя правильно, так как в вашем примере имя foo при вызове из call_foo не зависит от шаблонного параметра.
Меня можно встретить на www.cpp.forum24.ru
Re: VC и GCC: разное поведение, а как д.б. по стандарту?
От: alex_public  
Дата: 27.03.12 12:27
Оценка:
Здравствуйте, stil.man, Вы писали:

SM>Я хочу понять, какое поведение как правильное определяется стандартом ?

SM>И как с этим вообще жить ? Почему так ?

Не знаю как в стандарте, не смотрел. Но поведение VC явно интуитивно логичнее. Т.к. интуитивно не должно быть различий в поведение шаблонных и обычных классов.
Re[2]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: vdimas Россия  
Дата: 27.03.12 15:13
Оценка: -1
Здравствуйте, uzhas, Вы писали:
U>более явно можно прописывать, что за функцию мы вызываем
U>
U>::foo(); // вызываем глобальную функцию
this->>foo(); // вызываем свою
U>


GCC вроде бы это съесть не сможет: this->foo();
Т.к. в области видимости this-> такого мембера нет.

Можно как-то так:
typedef public Base<T> base;
base::foo();
Re[2]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: vdimas Россия  
Дата: 27.03.12 15:15
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Не знаю как в стандарте, не смотрел. Но поведение VC явно интуитивно логичнее. Т.к. интуитивно не должно быть различий в поведение шаблонных и обычных классов.


Не логичней. В момент определения шаблона никакого мембера foo нет, а глобальная foo есть.
Re[3]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: uzhas Ниоткуда  
Дата: 27.03.12 15:32
Оценка:
Здравствуйте, vdimas, Вы писали:

V>GCC вроде бы это съесть не сможет: this->foo();

сможет: http://liveworkspace.org/code/325a42b957b38b909add41d8c766f7ed
Re[3]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: Erop Россия  
Дата: 27.03.12 17:22
Оценка: +1
Здравствуйте, vdimas, Вы писали:

V>Т.к. в области видимости this-> такого мембера нет.


this, очевидно зависит от параметров шаблона, так что разрешенеи имён его методов откладывается на вторую стадию.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: VC и GCC: разное поведение, а как д.б. по стандарту?
От: Erop Россия  
Дата: 27.03.12 17:25
Оценка: +1
Здравствуйте, stil.man, Вы писали:

SM>Я не хочу вдаваться в такие вещи как "two-phase name lookup" или ADL, потому что все таки это особенности реализации компиляторов, и в стандарте о них нет ни слова.


Пример, тем не менее, именно на это

SM>Я хочу понять, какое поведение как правильное определяется стандартом ?

Как у gcc

SM>И как с этим вообще жить ?


Ну лучше всего не допускать в программе использования таких выражений, смысл которых зависит от места употребления

SM>Почему так ?

Ну потому, что хорошего решения данной проблемы нет. Мне одно время аргументация коммитета казалось логичной, но я попробовал писать и так и так, и понял, что нифига не помогает two-phase name lookup от РЕАЛЬНЫХ проблем, а вот неинтуитивности и писанины добавляет. Так что лично мне подход от MS нравится больше. Но лучше всего писать так, что бы оба подхода давали один и тот же результат...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: Lucky Cat  
Дата: 27.03.12 18:17
Оценка:
Здравствуйте, stil.man, Вы писали:

LC>>

LC>>GCC (4.7.0) error required from here в строке 31:Derived<int> h;

LC>>

SM>Чё это он ?.... странна. Все же валидно.

Разобрался. Это CodeBlocks принимает предупреждения за ошибки, ИЧСХ warning за ошибку не считает.
А у меня самосборные компиляторы на русском ругаются
Re[2]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: Кодт Россия  
Дата: 28.03.12 03:56
Оценка: 3 (1)
Здравствуйте, Erop, Вы писали:

SM>>Почему так ?

E>Ну потому, что хорошего решения данной проблемы нет. Мне одно время аргументация коммитета казалось логичной, но я попробовал писать и так и так, и понял, что нифига не помогает two-phase name lookup от РЕАЛЬНЫХ проблем, а вот неинтуитивности и писанины добавляет. Так что лично мне подход от MS нравится больше. Но лучше всего писать так, что бы оба подхода давали один и тот же результат...

Реальная проблема — это нарушение ODR.
Вот представь себе, что inline-функция проводит поиск имён только на второй фазе, в точке использования.
// foo.h
inline void foo() { cout << "hello " << bar(0) << endl; }
#define FOO() ((void)( cout << "hello " << bar(0) << endl; )) // полный аналог

// a.cpp
#include "foo.h" // объявление foo идёт перед объявлением зависимости, это существенно
const char* bar(char) { return "a"; }
void aaa() { foo(); FOO(); }

// b.cpp
#include "foo.h"
const char* bar(int) { return "b"; }
void bbb() { foo(); FOO(); }

// main.cpp
void aaa();
void bbb();
int main() { aaa(); bbb(); }

В результате имеем два конкурирующих разных определения функции.
Бред и фигня?
Компилятор воспротивится: даст ошибку на отсутствующей зависимости — имени bar. Вот с макросом прокатит, но это уже настоящий инлайн, так и должно быть.

А теперь то же самое с шаблонами?
// foo.h
template<class T> struct Foo : T
{
  void hello() const { cout << "hello " << bar(0) << endl; }
};
struct V {};

// a.cpp
#include "foo.h"
const char* bar(char) { return "a"; }
void aaa() { Foo<V>().hello(); }

// a.cpp
#include "foo.h"
const char* bar(int) { return "b"; }
void bbb() { Foo<V>().hello(); }
Перекуём баги на фичи!
Re[3]: VC и GCC: разное поведение, а как д.б. по стандарту?
От: wander  
Дата: 28.03.12 04:31
Оценка:
Здравствуйте, stil.man, Вы писали:

s> Можете дать конкретную ссылку если хотите.


Вот
Автор: pepsicoca
Дата: 09.11.10
, в принципе все подобные темы назывались примерно как эта.
avalon 1.0rc3 build 426, zlib 1.2.3
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.