С vs С++

Все, что вы хотели знать о программизме, но боялись спросить.
i_van
Завсегдатай
Сообщения: 251
Зарегистрирован: 09 сен 2004, 23:58

С vs С++

Сообщение i_van »

Всегда думал, что С++ как минимум advanced C. Но жизнь иногда ставит в тупик. При попытке миграции с С на С++ возникла проблема, описанная ниже. Пару решений я нашел, но они кривоваты.

Специалисты по С++ подтягиваемся:

Проблема связана с сигнатурой функции greeting. Код приведенный ниже работает в С, но не в С++. Как его элегантно заставить работать в С++?

#include <stdio.h>
void use_int(int *);
void use_float(float *);
void greeting(void (*)(void *), void *);

int main(void) {

int i_age = 22;
float f_age = 22.0;
void *p;

p = &i_age;
greeting(use_int, p); //first call

p = &f_age;
greeting(use_float, p); //second call

//getchar();
return 0;
}

void greeting(void (*fp)(void *), void *q) {
fp(q);
}

void use_int(int *r) {
int a;
a = * (int *) r;
printf("As an integer, you are %d years old.\n", a);
}
void use_float(float *s) {
float *b;
b = (float *) s;
printf("As a float, you are %f years old.\n", *b);
}
Аватара пользователя
ajkj3em
Маньяк
Сообщения: 2063
Зарегистрирован: 12 ноя 2006, 06:53

Re: С vs С++

Сообщение ajkj3em »

void use_int(void *r) {
int a;
a = * (int *) r;
printf("As an integer, you are %d years old.\n", a);
}
void use_float(void *s) {
float *b;
b = (float *) s;
printf("As a float, you are %f years old.\n", *b);
}

вто если дешево и сердито

* перевод с транслита
Аватара пользователя
Azazello
Житель
Сообщения: 769
Зарегистрирован: 16 янв 2007, 04:31

Сообщение Azazello »

Deleted: ajkj3em was first ;)...
Аватара пользователя
sz
Маньяк
Сообщения: 1266
Зарегистрирован: 17 фев 2003, 19:34

Re: С vs С++

Сообщение sz »

ajkj3em писал(а):void use_int(void *r) {
int a;
a = * (int *) r;
printf("As an integer, you are %d years old.\n", a);
}
void use_float(void *s) {
float *b;
b = (float *) s;
printf("As a float, you are %f years old.\n", *b);
}

вто если дешево и сердито

* перевод с транслита
На плюсах нынче кошернее писать:
a = * reinterpret_cast<int*>( r );
i_van
Завсегдатай
Сообщения: 251
Зарегистрирован: 09 сен 2004, 23:58

Re: С vs С++

Сообщение i_van »

ajkj3em писал(а):void use_int(void *r) {
int a;
a = * (int *) r;
printf("As an integer, you are %d years old.\n", a);
}
void use_float(void *s) {
float *b;
b = (float *) s;
printf("As a float, you are %f years old.\n", *b);
}

вто если дешево и сердито
* перевод с транслита
Я так и выкрутился. Однако при этом use_int() теряет строгое типизирование и может быть вызвана не с первоначально требуемым аргументом int* . В этом-то я и вижу кривизну, которой хотелось бы избежать.
Аватара пользователя
sz
Маньяк
Сообщения: 1266
Зарегистрирован: 17 фев 2003, 19:34

Сообщение sz »

Так оно и до этого было нестрого типизированно.
Так что, ничего не потерялось.
Аватара пользователя
ajkj3em
Маньяк
Сообщения: 2063
Зарегистрирован: 12 ноя 2006, 06:53

Re: С vs С++

Сообщение ajkj3em »

i_van писал(а):Я так и выкрутился. Однако при этом use_int() теряет строгое типизирование и может быть вызвана не с первоначально требуемым аргументом int* . В этом-то я и вижу кривизну, которой хотелось бы избежать.
строгое типизирование теряетcя при первом downcast'е в void.

в оригинальном коде ничего не мешает вызвать greeting(use_int, &f_age),
так шта кривизна там присутcтвует и без С++
Аватара пользователя
aissp
Маньяк
Сообщения: 2710
Зарегистрирован: 07 ноя 2005, 09:51

Сообщение aissp »

something like this
template <typename T> void func( void (*fp)(T*), T* q) {
fp(q);
}

calling:
void use_int(int* );
int q;

func(use_int, &q); //u don't need use template keyword here

sorry, havent time to check



good luck
Аватара пользователя
Azazello
Житель
Сообщения: 769
Зарегистрирован: 16 янв 2007, 04:31

Сообщение Azazello »

Ну, если templates использовать, то пожалуй так можно:

Код: Выделить всё

#include <iostream>
#include <typeinfo>

using namespace std;

template < typename TType > struct TypeTraits
  {
  };

struct TypeTraits< int >
 {
  static inline void SetPrecision( void )
   {
    cout << dec;
   }
 };

struct TypeTraits< float >
 {
  static inline void SetPrecision( void )
   {
    cout << fixed;
   }
 };

struct TypeTraits< double >
 {
  static inline void SetPrecision( void )
   {
    cout << scientific;
   }
 };

template < typename TType > void Greetings( TType fAge )
 {
  TypeTraits< TType > :: SetPrecision();

  cout << "In "<< typeid( TType ).name() << "-type representation, your are " << fAge << " years old." << endl;
 }

int main( void )
 {
  int lAgeI = 22;
  float lAgeF = 22;
  double lAgeD = 22;

  Greetings( lAgeI );
  Greetings( lAgeF );
  Greetings( lAgeD );

  cin.get();

  return( 0 );
 }
Program output писал(а): In int-type representation, you are 22 years old.
In float-type representation, you are 22.000000 years old.
In double-type representation, you are 2.200000e+01 years old.
Аватара пользователя
ajkj3em
Маньяк
Сообщения: 2063
Зарегистрирован: 12 ноя 2006, 06:53

Сообщение ajkj3em »

Azazello писал(а):Ну, если templates использовать, то пожалуй так можно:
http://www.ariel.com.au/jokes/The_Evolu ... ammer.html

:-)
Аватара пользователя
aissp
Маньяк
Сообщения: 2710
Зарегистрирован: 07 ноя 2005, 09:51

Сообщение aissp »

ну если мы все хором извращаемся то вынужден поправить код :)

Код: Выделить всё

template < typename TType, typename MyTraits = TypeTriats<TType> > void Greetings( TType fAge ) 
 { 
  MyTraits :: SetPrecision(); 

  cout << "In "<< MyTraits::name() << "-type representation, your are " << fAge << " years old." << endl; 
 } 


name() соотвественно тоже должна обрабатываться в классе свойств. Смысл так делать много и никакого одновременно
Аватара пользователя
Azazello
Житель
Сообщения: 769
Зарегистрирован: 16 янв 2007, 04:31

Сообщение Azazello »

I like the Master Programmer version ;)...
name() соотвественно тоже должна обрабатываться в классе свойств.
С MyTraits согласен - это более "правильный" стиль (торопился, у меня проф. сидел на шее ;)). А вот по поводу того, класть ли name() в TypeTraits - не уверен. Аргумент такой - в Traits кладутся только разные вещи, а то что можно объединить, надо объединять, иначе код разбухает бесцельно. assip, я правильно понимаю, что Ваш комментарий стилистический и заключается в том, что TypeInfo по своей сути вещь различная для типов и, соответственно, это должно быть отражено в Traits? Или я что-то принципиальное здесь упустил?
Аватара пользователя
aissp
Маньяк
Сообщения: 2710
Зарегистрирован: 07 ноя 2005, 09:51

Сообщение aissp »

лучше на ты а то у меня шок культурный сразу :)

Вобшем да ты прав, только уточню - трайтс класс уточнений, на етапе проихводства трайтса ты абсолютно точно знаешь тип вызова (для етого класс и служит не так ли?) поетому вызов typeId отпадает сам собой. Мне кажется не очень хороший стиль, когда по сути есть два различных места хранения инфо о типе. ДА и не верю я в корректную работу тайпАйдИ :) (ето основная причина)
Аватара пользователя
Azazello
Житель
Сообщения: 769
Зарегистрирован: 16 янв 2007, 04:31

Сообщение Azazello »

aissp писал(а):Мне кажется не очень хороший стиль, когда по сути есть два различных места хранения инфо о типе. ДА и не верю я в корректную работу тайпАйдИ :) (ето основная причина)
Согласен - некрасиво дублировать. Просто, RTTI всё равно нужно для dynamic_cast и virtual destructor clean-up, а, значит, TypeInfo уже есть. aissp, то есть, Вы dynamic_cast совсем не пользуете (просто интересно, как люди пишут ;)) или там какие-то конкретные проблемы с typeid (он же, по моему, просто возвращает ссылку на const type_info)?
Да, простите за "Вы" - привычка ;)...
Аватара пользователя
aissp
Маньяк
Сообщения: 2710
Зарегистрирован: 07 ноя 2005, 09:51

Сообщение aissp »

да за вы надо отучаться. А то представляешь типа Дорогой иван данилыч косячек то не отсасывайте и не мусольте, передавайте по кругу поджалста... :)

там с темплатами по коду нигде никакой виртальности нету :) точнее она есть но на етапе компиляции тока. А с динамиком - мне кажется единственное место где он применяется ето когда условия изменились настолько что надо передизайнить а на ето нету времени, либо код совсем чужой и никакими адаптерами не спасешься - действия должны происходить внутри кода.

ну например у тя есть список коров и свиней для скотобойни (их с ферм списывают на мфсозаготовки по старости) и все замечательно они у тебя живут под классом жЫвотное. Вдруг оказывается что что у свиней с украины бывает по три ноги и их надо обрабатывать особо. Хозяин библиотеки добавляет функцию bool is3LegExist() которую не вставляет в оьщий интерфейс. и тебе уже передизайнить нету времени - вот тут тебе приходится использовать динамик каст. Если такие запросы на количество заслуженных украниских свинок редки, ты забиваешь на все и делаешь нисъодящее приведение. Мне кажется так. Красивый пример никак в голову не лезет. сорри

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

Все сказанное мое сугубое имху
Ответить