Вариации на тему деклараций
От: rg45 СССР  
Дата: 07.12.09 21:45
Оценка: 159 (16)
Привет всем!

Прошу прощения, если баян, но я, мягко говоря, удивлен.

Как вы считаете, имеет ли какой-нибудь смысл, например, такое объявление:
typedef int Foo(const char*) const;

и в какой области такое объявление может располагаться? Оказывается, имеет и может располагаться вне определения класса, не смотря на модификатор const.

А вот вполне себе well-formed программка, можете откомпилировать и запустить. Обратите внимание на объявления и определения свободных функций и функций-членов:
#include <string>
#include <iostream>

typedef std::string Foo(const char*);
typedef std::string Goo(const char*) const;

//Свободные функции
Foo f1;
Foo f2;
Foo f3;

std::string f1(const char* str) { return "f1 -- " + std::string(str); }
std::string f2(const char* str) { return "f2 -- " + std::string(str); }
std::string f3(const char* str) { return "f3 -- " + std::string(str); }

//Функции-члены
struct A
{
  Foo f1;
  Foo f2;
  Foo f3;
  
  Goo g1;
  Goo g2;
  Goo g3;
};

std::string A::f1(const char* str) { return "A::f1 -- " + std::string(str); }
std::string A::f2(const char* str) { return "A::f2 -- " + std::string(str); }
std::string A::f3(const char* str) { return "A::f3 -- " + std::string(str); }

std::string A::g1(const char* str) const { return "A::g1 -- " + std::string(str); }
std::string A::g2(const char* str) const { return "A::g2 -- " + std::string(str); }
std::string A::g3(const char* str) const { return "A::g3 -- " + std::string(str); }

//Использование
int main()
{
  A a;

  std::cout << f1("abc") << std::endl;
  std::cout << f2("def") << std::endl;
  std::cout << f3("ghi") << std::endl;

  std::cout << a.f1("jkl") << std::endl;
  std::cout << a.f2("mno") << std::endl;
  std::cout << a.f3("pqr") << std::endl;

  std::cout << a.g1("stu") << std::endl;
  std::cout << a.g2("vwx") << std::endl;
  std::cout << a.g3("yza") << std::endl;
}


А вот пункт стандарта, который все это благословляет: 9.3/9. Для тех, у кого нет под рукой стандарта цитирую:

[Note: a member function can be declared (but not defined) using a typedef for a function type. The resulting member function has exactly the same type as it would have if the function declarator were provided explicitly, see 8.3.5. For example,

typedef void fv(void);
typedef void fvc(void) const;
struct S {
fv memfunc1; // equivalent to: void memfunc1(void);
void memfunc2();
fvc memfunc3; // equivalent to: void memfunc3(void) const;
};
fv S::* pmfv1 = &S::memfunc1;
fv S::* pmfv2 = &S::memfunc2;
fvc S::* pmfv3 = &S::memfunc3;

Also see 14.3. ]

--
Справедливость выше закона. А человечность выше справедливости.
Re: Вариации на тему деклараций
От: Erop Россия  
Дата: 08.12.09 00:09
Оценка: 45 (6)
Здравствуйте, rg45, Вы писали:

R>Прошу прощения, если баян, но я, мягко говоря, удивлен.

Интересно, почему эту фичу редко используют для безопасного объявления виртуальных функций?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: доигрались
От: Pavel Dvorkin Россия  
Дата: 08.12.09 11:47
Оценка: 14 (2) +2

struct A
{
  virtual Foo h = 0;
  Foo f1;
  Foo f2;
  Foo f3;
  
  Goo g1;
  Goo g2;
  Goo g3;
};

std::string A::h(const char* p)
{
    return p; // sorry! :-)
}


========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Это как все понимать ?
With best regards
Pavel Dvorkin
Re[7]: доигрались
От: rg45 СССР  
Дата: 09.12.09 09:02
Оценка: +4
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, rg45, Вы писали:


R>>Тебя удивляет, что компилятор не возражает против определения чисто виртуальной функции?


PD>Возражает


1>>e:\45555252\1.cpp(11) : error C2259: 'A' : cannot instantiate abstract class

1>> due to following members:
1>> 'void A::f(void)' : is abstract
1>> e:\45555252\1.cpp(2) : see declaration of 'A::f'


>>Ты еще больше удивишься когда узнаешь, что это полностью соответствет стандарту, см. 10.4/2.


PD>Значит, VC 2008 не соответствует стандарту


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


PD>Как видишь, в VC2008 нельзя.


Ну у нас получается разговор слепого с глухим, честное слово. Обрати внимание на выделенные фразы. Я говорю: "можно определять чисто виртуальные функции", а ты мне возражаешь: "нет, объекты абстрактных классов создавать нельзя" . На самом деле оба эти утверждения верны и друг другу не противоречат. Объекты абстрактных классов действительно нельзя создавать, но при этом можно давать определения чисто виртуальных функций классов этих объектов.

А все недоразумение началось из-за неполноты приведенного тобой примера: здесь
Автор: Pavel Dvorkin
Дата: 08.12.09
. По этому фрагменту и комментариям в нем можно сделать только один вывод, что ты не знаешь о том, что у чисто виртуальных функций могут быть определения. Но, как я теперь уже понимаю благодаря постам других участников, ты хотел именно сказать о глюках майкрософтовских компиляторов, которые пропускают создание объектов абстрактных классов. Это действительно ценные сведения, спасибо.
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: Ещё вариации: несколько функций, операторы
От: Alexey F  
Дата: 08.12.09 15:37
Оценка: 15 (2)
Здравствуйте, Alexander G, Вы писали:

AG>
[...skip...]
AG>struct Y {
AG>  G operator++; // gcc (mingw) 4.4.1 - error: declaration of 'operator++' as non-function
AG>};
[...skip...]
AG>

Не сработало

AG>забавно.

Да, можно было бы вообще вот так забавляться:
struct Y {
    form<Y>::prefix operator++;
    form<Y>::postfix operator++;
};


Re: Вариации на тему деклараций
От: jazzer Россия Skype: enerjazzer
Дата: 08.12.09 10:37
Оценка: 13 (2)
Здравствуйте, rg45, Вы писали:

R>Привет всем!


R>Прошу прощения, если баян, но я, мягко говоря, удивлен.


R>Как вы считаете, имеет ли какой-нибудь смысл, например, такое объявление:

R>
R>typedef int Foo(const char*) const;
R>

R>и в какой области такое объявление может располагаться? Оказывается, имеет и может располагаться вне определения класса, не смотря на модификатор const.

gcc 3.4.6 не поддерживает консты
e.cpp:189: error: invalid type qualifier for non-member function type
e.cpp:189: error: `const' and `volatile' function specifiers on `Foo' invalid in type declaration



Как обычно, макросы нас спасут (и заодно будут работать и для определений, не только для объявлений) :
#define DECLARE(sig, name) sig(,name)
#define DEFINE(sig, class, name) sig(class::,name)

// signatures
#define SIG1(class, name) void class name(int i, double d)
#define SIG2(class, name) void class name(double d, int i) const

// better name for SIG1
#define DECLARE_CALLBACK(name) DECLARE(SIG1, name)
#define DEFINE_CALLBACK(class, name) DEFINE(SIG1, class, name)

struct A
{
  DECLARE(SIG1, f1);
  DECLARE(SIG2, g);
  
  DECLARE_CALLBACK(f2);
};

DEFINE(SIG1, A, f1)
{
}

DEFINE(SIG2, A, g)
{
}

DEFINE_CALLBACK(A, f2)
{
}


брюки превращаются вот в такой код:
struct A
{
  void f1(int i, double d);
  void g(double d, int i) const;

  void f2(int i, double d);
};

void A:: f1(int i, double d)
{
}

void A:: g(double d, int i) const
{
}

void A:: f2(int i, double d)
{
}
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: +Параметры по-умолчанию
От: Юрий Жмеренецкий ICQ 380412032
Дата: 11.12.09 00:59
Оценка: 13 (2)
Здравствуйте, Alexey F, Вы писали:

AF>Здравствуйте, rg45, Вы писали:


AF>...И, конечно же , такое:

AF>
AF>// Называется "попробуй не специально сделать различные параметры по-умолчанию у предка
AF>// и наследника в виртуальных функциях при соблюдении такого синтаксиса":
AF>typedef void SomeMethod ( int = 42 ) const;


AF>struct A {
AF>    virtual SomeMethod m = 0;
AF>};


AF>struct B : A {
AF>    virtual SomeMethod m;
AF>};


AF>void B::m ( int ) const {

AF>}
AF>

AF>ИМХО, такие typedef-ы (я не про параметры по-умолчанию, а вообще) — очень крутая фича

Параметры по умолчанию (как и exception specification) не могут быть использованы в таком контексте (8.3.6/3, 15.4/1).
Re[3]: Вариации на тему деклараций
От: Юрий Жмеренецкий ICQ 380412032
Дата: 11.12.09 00:17
Оценка: 8 (1) +1
Здравствуйте, rg45, Вы писали:

R> А выглядит, конечно, непривычно:

R>
R>struct A
R>{
R>  virtual Foo foo = 0;
R>};
R>

Можно пойти дальше:

struct A
{
  typedef int X();
  typedef int Y() const;
  template<class> X Z;
  template<class> Y Z;
};
Re[3]: Вариации на тему деклараций
От: rg45 СССР  
Дата: 08.12.09 11:24
Оценка: +1 :)
Здравствуйте, yatagarasu, Вы писали:

Y>Здравствуйте, Erop, Вы писали:


E>>Здравствуйте, rg45, Вы писали:


R>>>Прошу прощения, если баян, но я, мягко говоря, удивлен.

E>>Интересно, почему эту фичу редко используют для безопасного объявления виртуальных функций?

Y>а в чем безопасность? и опасность старого метода?


В том, что легко допустить незначительную ошибку в сигнатуре и вместо переопределения виртуальной функции получить сокрытие, например:
class A
{
public:
  virtual int foo(int) const;
};

class B : public A
{
public:
  virtual int foo(int); //Забыли модификатор const и получили новую функцию вместо перекрытия существующей
};

И хорошо, если компилятор выдаст предупреждение.

А такой вариант дает больше уверенности:
typedef int Foo(int) const;
class A
{
public:
  virtual Foo foo;
};

class B : public A
{
public:
  virtual Foo foo; //virtual можно даже не писать в этом месте, его обычно пишут для большей наглядности
};
--
Справедливость выше закона. А человечность выше справедливости.
Re[5]: доигрались
От: yatagarasu Беларусь  
Дата: 08.12.09 12:18
Оценка: 14 (1)
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>

PD>struct A
PD>{
PD>  virtual Foo h = 0;
PD>  Foo f1;
PD>  Foo f2;
PD>  Foo f3;
  
PD>  Goo g1;
PD>  Goo g2;
PD>  Goo g3;
PD>};

PD>std::string A::h(const char* p)
PD>{
PD>    return p; // sorry! :-)
PD>}

PD>


PD>========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========


PD>Это как все понимать ?


C:/devkitPro/projects/sandbox/test/src/serialization.h:200: error: cannot allocate an object of abstract type 'A'
C:/devkitPro/projects/sandbox/test/src/serialization.h:41: note: because the following virtual functions are pure within 'A':
C:/devkitPro/projects/sandbox/test/src/serialization.h:111: note: virtual bool A::h(const char *)
gcc 4.4

msvc 2010 beta 2 ведет себя так же как и 2008
Re[5]: таки да, доигрались
От: Alexander G Украина  
Дата: 08.12.09 13:07
Оценка: 14 (1)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Это как все понимать ?


Нужно полностью код приводить
тут баг не то что бывают чисто виртуальные функции, а то, что с ними можно создать экземпляр класса.

pure specifier, видимо, почти игнорируется.

typedef void G (int);

struct X
{
    G f1 = 0;
};

int main()
{
    X y;
}


и даже


typedef void G (int);

union X
{
    G f1 = 666;
};

int main()
{
    X y;
}
Русский военный корабль идёт ко дну!
Re[3]: Вариации на тему деклараций
От: Pavel Dvorkin Россия  
Дата: 08.12.09 11:41
Оценка: 7 (1)
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, Erop, Вы писали:


E>>Здравствуйте, rg45, Вы писали:


R>>>Прошу прощения, если баян, но я, мягко говоря, удивлен.

E>>Интересно, почему эту фичу редко используют для безопасного объявления виртуальных функций?

R>Я вообще никогда раньше не встречал таких объявлений функций-членов, ни виртуальных ни невиртуальных. А выглядит, конечно, непривычно:

R>
R>struct A
R>{
R>  virtual Foo foo = 0;
R>};
R>


Гм...

Берем твой пример и делаем так


struct A
{
  virtual Foo h = 0;
  Foo f1;
  Foo f2;


1>4777777.obj : error LNK2001: unresolved external symbol "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall A::h(char const *)" (?h@A@@UAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@PBD@Z)


А теперь так, явно


struct A
{
  virtual std::string Moo(const char*) = 0;
  Foo f1;
  Foo f2;


1>e:\4777777\4777777.cpp(45) : error C2259: 'A' : cannot instantiate abstract class


VC 2008

Получается, что в первом случае класс не явялется абстрактным, несмотря на наличие чисто вирт. функции ?
With best regards
Pavel Dvorkin
Re: Ещё вариации: несколько функций, операторы
От: Alexander G Украина  
Дата: 08.12.09 14:58
Оценка: 7 (1)
typedef int G (void);

struct X {
  G f1 , f2;
};

struct Y {
  G operator++;
};

int main() {
  X x;
  Y y;
}


забавно.
Русский военный корабль идёт ко дну!
Re: Вариации на тему деклараций
От: Юрий Жмеренецкий ICQ 380412032
Дата: 09.12.09 18:15
Оценка: 7 (1)
Здравствуйте, rg45, Вы писали:


R>Как вы считаете, имеет ли какой-нибудь смысл, например, такое объявление:

R>
R>typedef int Foo(const char*) const;
R>

R>и в какой области такое объявление может располагаться? Оказывается, имеет и может располагаться вне определения класса, не смотря на модификатор const.

Кстати, в Active Issue 547 предлагается ослабить ограничение на допустимые места, в которых можно использовать квалификатор const и разрешить такое:

template<class T> struct X;

// partial specialization for a const member function:
template<class R> struct X< R() const > 
{};



R>А вот пункт стандарта, который все это благословляет: 9.3/9.


Не совсем: 8.3.5/4 разрешает использование cv-qualifier в typedef declaration для top-level function type, а 8.3.5/7 разрешает использовать объявленные таким образом имена при объявлении функций-членов. С volatile такой фокус также проходит.
Re: Вариации на тему деклараций
От: Тот кто сидит в пруду Россия  
Дата: 07.12.09 21:54
Оценка: 1 (1)
Здравствуйте, rg45, Вы писали:

R>Прошу прощения, если баян, но я, мягко говоря, удивлен.


R>Как вы считаете, имеет ли какой-нибудь смысл, например, такое объявление:

R>
R>typedef int Foo(const char*) const;
R>

R>и в какой области такое объявление может располагаться? Оказывается, имеет и может располагаться вне определения класса, не смотря на модификатор const.

Для объявления членов класса я такую фишку уже 5 лет использую, в самодельном rpc. Мне там тип члена нужен, который по другому выцарапать не удалось. Поэтому в одном макросе сначала объявляю тип члена, потом, пользуясь этим типом, саму функцию. Допускаю что кому нибудь в аналогичных целях может и вне класса пригодиться.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re: Вариации на тему деклараций
От: rg45 СССР  
Дата: 08.12.09 11:07
Оценка: +1
Здравствуйте, rg45, Вы писали:

R>Прошу прощения, если баян, но я, мягко говоря, удивлен.

R>...

Еще маленький нюанс. Также, как для объявленных "традиционным" образом перегруженных функций-членов, при таком способе объявления также допустимо повторное использование идентификаторов:
typedef void X();
typedef void Y() const;
typedef void Z(int);

struct A
{
  X foo;
  Y foo;
  Z foo;
};
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: Вариации на тему деклараций
От: rg45 СССР  
Дата: 08.12.09 11:12
Оценка: +1
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, rg45, Вы писали:


R>>Прошу прощения, если баян, но я, мягко говоря, удивлен.

E>Интересно, почему эту фичу редко используют для безопасного объявления виртуальных функций?

Я вообще никогда раньше не встречал таких объявлений функций-членов, ни виртуальных ни невиртуальных. А выглядит, конечно, непривычно:
struct A
{
  virtual Foo foo = 0;
};
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: Вариации на тему деклараций
От: jazzer Россия Skype: enerjazzer
Дата: 08.12.09 11:24
Оценка: +1
Здравствуйте, yatagarasu, Вы писали:

Y>а в чем безопасность? и опасность старого метода?


В том, что если ты ошибаешься в сигнатуре перекрытого метода, то он перестаёт быть перекрытым и становится перегруженным, скрывая оригинал.
Со всеми вытекающими.
Ну и аналогично при смене сигнатуры в базовом классе.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[6]: доигрались
От: Pavel Dvorkin Россия  
Дата: 09.12.09 08:17
Оценка: -1
Здравствуйте, rg45, Вы писали:

R>Тебя удивляет, что компилятор не возражает против определения чисто виртуальной функции?


Возражает


class A{
    virtual void f() = 0;
};

void A::f()
{
}

int main()
{
    A a;
    return 0;
}


1>e:\45555252\1.cpp(11) : error C2259: 'A' : cannot instantiate abstract class

1> due to following members:
1> 'void A::f(void)' : is abstract
1> e:\45555252\1.cpp(2) : see declaration of 'A::f'


>Ты еще больше удивишься когда узнаешь, что это полностью соответствет стандарту, см. 10.4/2.


Значит, VC 2008 не соответствует стандарту


>Этот вопрос не раз обсуждался на форума и в Q&A есть ссылка: А чисто виртуальные деструкторы &mdash; бывают?
Автор: Павел Кузнецов
Дата: 03.04.03
.А еще можешь переделать свой пример для "традиционнго" объявления, ты убедишься, что в этом случае можно определить чисто виртуальную функцию. Только, на всякий случай, определение чисто виртуальной функции болжно быть выполнено за пределами определения класса согласно все тому же пункту стандарта.


Как видишь, в VC2008 нельзя.
With best regards
Pavel Dvorkin
Re: Вариации на тему деклараций
От: rg45 СССР  
Дата: 07.12.09 22:21
Оценка:
Здравствуйте, rg45, Вы писали:

R>Как вы считаете, имеет ли какой-нибудь смысл, например, такое объявление:

R>
R>typedef int Foo(const char*) const;
R>

R>...

Думаю, полезное применение для этой фичи найдется быстро. Например, для случаев, когда объявляется большое количество функций с одинаковой сигнатурой. Причем, прелесть в том, что один и тот же typedef одновременно используется как свободными функциями, так и функциями-членами классов, причем, разных классов! При необходимости одним махом можно изменить все объявления. Правда, определения все равно прийдется лопатить врукопашную, но тут уже копмилятор не даст ошибиться и пропустить какое-то определение.

Еще применение: это дополнительное средство повышения читабельности объявления указателей на функции члены. Например, вместо
struct A
{
  std::string foo(int, double, const char*) const;
};
struct B
{
  std::string foo(int, double, const char*) const;
};

typedef std::string (A::*A_Foo)(int, double, const char*) const;
typedef std::string (B::*B_Foo)(int, double, const char*) const;

A_Foo a_foo = &A::foo;
B_Foo b_foo = &B::foo;

можно писать:
typedef std::string Foo(int, double, const char*) const;

struct A { Foo foo; };
struct B { Foo foo; };

Foo A::*a_foo = &A::foo;
Foo B::*b_foo = &B::foo;
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: Вариации на тему деклараций
От: yatagarasu Беларусь  
Дата: 08.12.09 11:15
Оценка:
Здравствуйте, Erop, Вы писали:

E>Здравствуйте, rg45, Вы писали:


R>>Прошу прощения, если баян, но я, мягко говоря, удивлен.

E>Интересно, почему эту фичу редко используют для безопасного объявления виртуальных функций?

а в чем безопасность? и опасность старого метода?
Re[3]: Вариации на тему деклараций
От: Erop Россия  
Дата: 08.12.09 11:23
Оценка:
Здравствуйте, yatagarasu, Вы писали:

Y>а в чем безопасность? и опасность старого метода?


В том, что поменяешь тип функции в базе, а в каком-нибудь из наследников забудешь...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[5]: доигрались
От: rg45 СССР  
Дата: 08.12.09 12:11
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>

PD>struct A
PD>{
PD>  virtual Foo h = 0;
PD>  Foo f1;
PD>  Foo f2;
PD>  Foo f3;
  
PD>  Goo g1;
PD>  Goo g2;
PD>  Goo g3;
PD>};

PD>std::string A::h(const char* p)
PD>{
PD>    return p; // sorry! :-)
PD>}

PD>


PD>========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========


PD>Это как все понимать ?


Тебя удивляет, что компилятор не возражает против определения чисто виртуальной функции? Ты еще больше удивишься когда узнаешь, что это полностью соответствет стандарту, см. 10.4/2. Этот вопрос не раз обсуждался на форума и в Q&A есть ссылка: А чисто виртуальные деструкторы &mdash; бывают?
Автор: Павел Кузнецов
Дата: 03.04.03
.А еще можешь переделать свой пример для "традиционнго" объявления, ты убедишься, что в этом случае можно определить чисто виртуальную функцию. Только, на всякий случай, определение чисто виртуальной функции болжно быть выполнено за пределами определения класса согласно все тому же пункту стандарта.
--
Справедливость выше закона. А человечность выше справедливости.
Re[6]: таки да, доигрались
От: wander  
Дата: 08.12.09 13:20
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, Pavel Dvorkin, Вы писали:


PD>>Это как все понимать ?


AG>Нужно полностью код приводить

AG>тут баг не то что бывают чисто виртуальные функции, а то, что с ними можно создать экземпляр класса.

AG>pure specifier, видимо, почти игнорируется.


AG>
AG>typedef void G (int);

AG>struct X
AG>{
AG>    G f1 = 0;
AG>};

AG>int main()
AG>{
AG>    X y;
AG>}
AG>


AG>и даже



AG>
AG>typedef void G (int);

AG>union X
AG>{
AG>    G f1 = 666;
AG>};

AG>int main()
AG>{
AG>    X y;
AG>}
AG>


В каком компиляторе? У меня в mingw 4.4 все прекрасно. Выдает ошибку как и положено.
Re[7]: таки да, доигрались
От: Alexander G Украина  
Дата: 08.12.09 13:47
Оценка:
Здравствуйте, wander, Вы писали:


W>В каком компиляторе? У меня в mingw 4.4 все прекрасно. Выдает ошибку как и положено.


default compiler

конкретно, в моём случае MSVC8 (VC 2005).
Русский военный корабль идёт ко дну!
Re[8]: таки да, доигрались
От: wander  
Дата: 08.12.09 13:59
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, wander, Вы писали:



W>>В каком компиляторе? У меня в mingw 4.4 все прекрасно. Выдает ошибку как и положено.


AG>default compiler


AG>конкретно, в моём случае MSVC8 (VC 2005).


Подозреваю, что эта проблема наблюдается только в MSVC.
Re[8]: таки да, доигрались
От: Тот кто сидит в пруду Россия  
Дата: 08.12.09 14:06
Оценка:
Здравствуйте, Alexander G, Вы писали:

W>>В каком компиляторе? У меня в mingw 4.4 все прекрасно. Выдает ошибку как и положено.


AG>default compiler


AG>конкретно, в моём случае MSVC8 (VC 2005).


7.1 кажись ругался.
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[2]: Ещё вариации: несколько функций, операторы
От: rg45 СССР  
Дата: 08.12.09 15:23
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>
AG>  G operator++;
AG>


В первую секунду был легкий ступор, только потом въехал в суть написанного
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: Ещё вариации: несколько функций, операторы
От: Alexander G Украина  
Дата: 08.12.09 15:52
Оценка:
Здравствуйте, Alexey F, Вы писали:

AF>Здравствуйте, Alexander G, Вы писали:


AG>>
AF>[...skip...]
AG>>struct Y {
AG>>  G operator++; // gcc (mingw) 4.4.1 - error: declaration of 'operator++' as non-function
AG>>};
AF>[...skip...]
AG>>

AF>Не сработало

Жаль, comeau, borland и msvc осилили

AG>>забавно.

AF>Да, можно было бы вообще вот так забавляться:
struct Y {
  form<Y>::prefix operator++;
  form<Y>::postfix operator++;
};




Интересная мысль, действительно более читабельные ++ и -- и не забудешь вернуть ссылку.

Даже так:
struct Y {
  form<Y>::prefix operator++, operator--;
  form<Y>::postfix operator++, operator--;
};
Русский военный корабль идёт ко дну!
Re[4]: Ещё вариации: несколько функций, операторы
От: yatagarasu Беларусь  
Дата: 10.12.09 20:05
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, Alexey F, Вы писали:


AF>>Здравствуйте, Alexander G, Вы писали:


AG>>>
AF>>[...skip...]
AG>>>struct Y {
AG>>>  G operator++; // gcc (mingw) 4.4.1 - error: declaration of 'operator++' as non-function
AG>>>};
AF>>[...skip...]
AG>>>

AF>>Не сработало

AG>Жаль, comeau, borland и msvc осилили


просвятите, а кто прав?
Re[5]: Ещё вариации: несколько функций, операторы
От: rg45 СССР  
Дата: 10.12.09 20:19
Оценка:
Здравствуйте, yatagarasu, Вы писали:

AG>>>>
AG>>>>struct Y {
AG>>>>  G operator++; // gcc (mingw) 4.4.1 - error: declaration of 'operator++' as non-function
AG>>>>};
AG>>>>

AG>>Жаль, comeau, borland и msvc осилили

Y>просвятите, а кто прав?


Рассмотрим все тот же пример из стандарта, п.9.3/9 (сокращено):
typedef void fv(void);
struct S {
fv memfunc1; // equivalent to: void memfunc1(void);
};


Согласно этому:
typedef int G (void);
struct Y {
  G operator++; // equivalent to: int operator++(void);
};


Конечно, сигнатура префиксного оператора инкремента выбрана не совсем удачно, но компилироваться-то должно.
--
Справедливость выше закона. А человечность выше справедливости.
Re: +Параметры по-умолчанию
От: Alexey F  
Дата: 11.12.09 00:40
Оценка:
Здравствуйте, rg45, Вы писали:

...И, конечно же , такое:
// Называется "попробуй не специально сделать различные параметры по-умолчанию у предка
// и наследника в виртуальных функциях при соблюдении такого синтаксиса":
typedef void SomeMethod ( int = 42 ) const;


struct A {
    virtual SomeMethod m = 0;
};


struct B : A {
    virtual SomeMethod m;
};


void B::m ( int ) const {

}

ИМХО, такие typedef-ы (я не про параметры по-умолчанию, а вообще) — очень крутая фича
Re[8]: доигрались
От: Pavel Dvorkin Россия  
Дата: 11.12.09 06:24
Оценка:
Здравствуйте, rg45, Вы писали:


R>А все недоразумение началось из-за неполноты приведенного тобой примера: здесь
Автор: Pavel Dvorkin
Дата: 08.12.09
. По этому фрагменту и комментариям в нем можно сделать только один вывод, что ты не знаешь о том, что у чисто виртуальных функций могут быть определения.


Определения быть могут, и это я знаю, но от того, что у чисто виртуальной функции появится определение, класс, содержащий такую функцию, не перестанет быть абстрактным , и инстансы его создавать нельзя. VC 2008 вполне следует этому правилу для явно описанных чисто виртуальных функций и не следует для описанных через этот самый typedef.


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


Дело не в том, что он пропускает. Он не считает этот класс абстрактным!!!


class A {
    virtual void f() = 0;
};

void A::f()
{
}

int _tmain(int argc, _TCHAR* argv[])
{
    A a;
    return 0;
}


Описание чисто вирт. функции есть, но тем не менее класс абстрактный

1>e:\4111111\4111111.cpp(16) : error C2259: 'A' : cannot instantiate abstract class

1> due to following members:
1> 'void A::f(void)' : is abstract
1> e:\4111111\4111111.cpp(7) : see declaration of 'A::f'

А теперь


typedef void F(void);

class A {
    virtual F f = 0;
};

void A::f()
{
}

int _tmain(int argc, _TCHAR* argv[])
{
    A a;
    return 0;
}


и программа замечательно начинает выполняться и экземпляр A a нормально создается!
With best regards
Pavel Dvorkin
Re[9]: доигрались
От: rg45 СССР  
Дата: 12.12.09 23:51
Оценка:
Здравствуйте, Pavel Dvorkin, Вы писали:

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


PD>Дело не в том, что он пропускает. Он не считает этот класс абстрактным!!!


Не пойму я что-то. Каковы отличительные признаки "допускает создание объектов абстрактного класса" от "не считает класс абстрактным"?
--
Справедливость выше закона. А человечность выше справедливости.
Re[10]: доигрались
От: Pavel Dvorkin Россия  
Дата: 14.12.09 02:26
Оценка:
Здравствуйте, rg45, Вы писали:

R>Не пойму я что-то. Каковы отличительные признаки "допускает создание объектов абстрактного класса" от "не считает класс абстрактным"?


А что же тут непонятного ? Если компилятор считает, что класс абстрактный, но при этом допускает создание экземпляров — это одно, это явная ошибка компилятора. Если же компилятор не считает класс абстрактным, тогда создавать экземпляры он имеет полное право, а вопрос же — верно ли он так считает ?
With best regards
Pavel Dvorkin
Re: Вариации на тему деклараций
От: sokel Россия  
Дата: 14.12.09 14:06
Оценка:
Здравствуйте, rg45, Вы писали:

R>...


Хм... можно тип функций шаблоном параметризовать:
#include <stdio.h>

template<typename T> struct t_foo { typedef void foo(T); };

struct A
{
    t_foo<int>::foo bar;
    t_foo<const char*>::foo bar;
};

void A::bar(int v) { printf("A::bar:%d\n", v); }
void A::bar(const char* v) { printf("A::bar:'%s'\n", v); }

int main()
{
    A test;
    test.bar(3);
    test.bar("str");
}


а на шаблонах можно и частичную специализацию сделать :
#include <stdio.h>

template<typename T> struct t_foo { typedef void foo(const T&);  };
template<> struct t_foo<const char*> { typedef void foo(const char*); };

template<typename T> struct A
{
    static typename t_foo<T>::foo bar;
};

template<> void A<int>::bar(const int& v) { printf("A::bar:%d\n", v); }
template<> void A<const char*>::bar(const char* v) { printf("A::bar:'%s'\n", v); }

int main()
{
    A<int>::bar(3);
    A<const char*>::bar("str");
}


зачем вот только, непонятно...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.