Если функция возвращает значения различных типов ...
От: ChainEG  
Дата: 19.08.09 09:35
Оценка:
Есть набор типов

typedef ... Type;

typedef ... TypeA; 
typedef ... TypeB;
typedef ... TypeC;


Есть функция, которая может возвращать значения различных типов.
Type Get(const char *sz);


Нужно инициализировать переменные различных типов
TypeA A;
TypeB B;
TypeC C;


Обычно, я делал так:
// Способ 1
A=(TypeA)Get("A");
B=(TypeB)Get("B");
C=(TypeC)Get("C");


Но вот, в чужом коде увидел такой прием:
// Способ 2
(Type&)A=Get("A");
(Type&)B=Get("B");
(Type&)C=Get("C");


Какой способ лучше?
Способ 1, на мой взгляд, интуимтивно понятнее.
Его недостаток — требуется следить, куда кастить каждое значение, и не ошибиться при этом.
Если названия типов TypeA, TypeB ... имеют разную длину, то код неаккуратно выглядит.

Способ 2 интуимтивно менее понятен, но, как мне кажется лучше читаем, так как четко видна основная цель выпажения: A=Get("A").
Не нужно следить за типами: все значения кастятся в один ти тот же тип.
И оформление кода получается более аккуратным

И все же, какой способ предпочтительнее?
Re: Если функция возвращает значения различных типов ...
От: jazzer Россия Skype: enerjazzer
Дата: 19.08.09 09:40
Оценка:
Здравствуйте, ChainEG, Вы писали:

CEG>Есть набор типов


CEG>
CEG>typedef ... Type;

CEG>typedef ... TypeA; 
CEG>typedef ... TypeB;
CEG>typedef ... TypeC;
CEG>


CEG>Есть функция, которая может возвращать значения различных типов.

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]: Если функция возвращает значения различных типов ...
От: ChainEG  
Дата: 19.08.09 09:48
Оценка:
Здравствуйте, jazzer, Вы писали:

CEG>>Есть функция, которая может возвращать значения различных типов.

В смысле, она возвращает значение некоего общего типа Type, которое предлагается откастить в нужный тип: TypeA, TypeB ...

Пример такой функции: GetProcAddress()
Re: Если функция возвращает значения различных типов ...
От: _Dreamer Россия  
Дата: 19.08.09 09:49
Оценка:
Здравствуйте, ChainEG, Вы писали:

CEG>Обычно, я делал так:

CEG>
CEG>// Способ 1
CEG>A=(TypeA)Get("A");
CEG>B=(TypeB)Get("B");
CEG>C=(TypeC)Get("C");
CEG>


CEG>Но вот, в чужом коде увидел такой прием:

CEG>
CEG>// Способ 2
CEG>(Type&)A=Get("A");
CEG>(Type&)B=Get("B");
CEG>(Type&)C=Get("C");
CEG>


CEG>И все же, какой способ предпочтительнее?


я бы примерно так сделал
template < typename ResultType >
ResultType GetTyped( const char * s )
{
  return (ResultType)Get(s);
}

template < typename ResultType >
void GetTyped( const char * s, ResultType& result )
{
  result = (ResultType)Get(s);
}

TypeA a = GetTyped<TypeA>("A");
GetTyped<TypeA>("A", a);
GetTyped("A", a); // указание типа можно опустить
Re: Если функция возвращает значения различных типов ...
От: NordSky Россия  
Дата: 19.08.09 09:56
Оценка:
Здравствуйте, ChainEG, Вы писали:

CEG>Есть набор типов


CEG>
CEG>typedef ... Type;

CEG>typedef ... TypeA; 
CEG>typedef ... TypeB;
CEG>typedef ... TypeC;
CEG>


CEG>Есть функция, которая может возвращать значения различных типов.

CEG>
CEG>Type Get(const char *sz);
CEG>


CEG>Нужно инициализировать переменные различных типов

CEG>
CEG>TypeA A;
CEG>TypeB B;
CEG>TypeC C;
CEG>


CEG>Обычно, я делал так:

CEG>
CEG>// Способ 1
CEG>A=(TypeA)Get("A");
CEG>B=(TypeB)Get("B");
CEG>C=(TypeC)Get("C");
CEG>


CEG>Но вот, в чужом коде увидел такой прием:

CEG>
CEG>// Способ 2
CEG>(Type&)A=Get("A");
CEG>(Type&)B=Get("B");
CEG>(Type&)C=Get("C");
CEG>


CEG>Какой способ лучше?

CEG>Способ 1, на мой взгляд, интуимтивно понятнее.
CEG>Его недостаток — требуется следить, куда кастить каждое значение, и не ошибиться при этом.
CEG>Если названия типов TypeA, TypeB ... имеют разную длину, то код неаккуратно выглядит.

CEG>Способ 2 интуимтивно менее понятен, но, как мне кажется лучше читаем, так как четко видна основная цель выпажения: A=Get("A").

CEG>Не нужно следить за типами: все значения кастятся в один ти тот же тип.
CEG>И оформление кода получается более аккуратным

CEG>И все же, какой способ предпочтительнее?


Есть stl а там есть тип pair,так на всякий случай
Re: Если функция возвращает значения различных типов ...
От: sokel Россия  
Дата: 19.08.09 10:50
Оценка: 1 (1)
Здравствуйте, ChainEG, Вы писали:


CEG>A=(TypeA)Get("A");

CEG>(Type&)A=Get("A");

CEG>Какой способ лучше?


Надо понимать, что это не эквивалентные выражения:
#include <stdio.h>

struct base 
{
    int i;
    base(int i = 0) : i(i) {} 
};
struct derived     : base 
{
    int j;
    derived() : j(0) {}
    derived(const base& b) : j(b.i), base(b) {}
};
base get() { return base(1); }

int main()
{
    derived d1, d2;
    d1 = (derived) get();
    (base&) d2 = get();
    printf("d1: %d,%d\n", d1.i, d1.j);
    printf("d2: %d,%d\n", d2.i, d2.j);
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1144>>
Re: Если функция возвращает значения различных типов ...
От: Кодт Россия  
Дата: 19.08.09 13:17
Оценка: 2 (1)
Здравствуйте, ChainEG, Вы писали:

CEG>Нужно инициализировать переменные различных типов

CEG>
CEG>TypeA A;
CEG>// Способ 1
CEG>A=(TypeA)Get("A");
CEG>// Способ 2
CEG>(Type&)A=Get("A");
CEG>


Во втором случае наблюдается очень прикольное природное явление.
1) static_cast
1.1) если TypeA унаследован от Type, выполняется up-cast (обращение к базовому подобъекту), и происходит частичное присваивание — срезка наоборот
1.2) если Type унаследован от TypeA, выполняется down-cast, причём
1.2.1) если Type двоично совместим с TypeA, происходит обычное присваивание (как в 2.1)
1.2.2) если нет — т.е. sizeof(Type)!=sizeof(TypeA), то, аналогично (2.4), мы запиливаем память вокруг объекта-приёмника (причём можем расстрелять и хвост, и голову! при ненулевом смещении базы)
2) reinterpret_cast
2.1) если типы двоично совместимы (int и long на IA32, например; или две структуры с совпадающим лэяутом), происходит обычное присваивание
2.2) если совместимы условно (int и unsigned int) — поведение платформенно-зависимо; обычно ничего трагичного в этом нет
2.3) если имеют одинаковый размер, но несовместимы (long и float) — получаем мусор и, по большому счёту, неопределённое поведение; особенно, если это не POD-типы
2.4) если разный размер — то вдобавок запиливаем память

Отсюда мораль: этот способ ошибкоопасный, очень ограниченно применимый и вдобавок платформенно-зависимый.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
http://files.rsdn.org/4783/catsmiley.gif Перекуём баги на фичи!
Re: Если функция возвращает значения различных типов ...
От: Кодт Россия  
Дата: 19.08.09 13:17
Оценка: 2 (2)
Здравствуйте, ChainEG, Вы писали:

CEG>Способ 1, на мой взгляд, интуимтивно понятнее.

CEG>Его недостаток — требуется следить, куда кастить каждое значение, и не ошибиться при этом.
CEG>Если названия типов TypeA, TypeB ... имеют разную длину, то код неаккуратно выглядит.

CEG>Способ 2 интуимтивно менее понятен, но, как мне кажется лучше читаем, так как четко видна основная цель выпажения: A=Get("A").

CEG>Не нужно следить за типами: все значения кастятся в один ти тот же тип.
CEG>И оформление кода получается более аккуратным

CEG>И все же, какой способ предпочтительнее?


На самом деле, при использовании GetProcAddress очень утомительно выписывать типы,
// прототип
// int __stdcall hello(const char* from, const char* to);

// ужас-ужас-ужас
int (__stdcall *fun)(const char*, const char*) = (int (__stdcall*)(const char*,const char*)) GetProcAddress("hello");
fun = (int (__stdcall*)(const char*,const char*)) GetProcAddress("goodbye");

// просто ужас
typedef int (__stdcall *GREETING)(const char*, const char*);
GREETING fun = (GREETING) GetProcAddress("hello");
fun = (GREETING) GetProcAddress("goodbye");

и хочется иметь какой-то вот такой
// не заводим ненужных typedef'ов
int (__stdcall* fun)(const char*, const char*) = (getproc_cast) GetProcAddress("hello");
fun = (getproc_cast) GetProcAddress("goodbye");

Это несложно:
struct getproc_cast
{
    FARPROC m_ptr; // результат GetProcAddress - тип, двоично совместимый с void(*)() и - особенности Windows - void*
    getproc_cast(FARPROC ptr) : m_ptr(ptr) {}
    template<class Ptr> operator Ptr() const { return (Ptr) m_ptr; }
};


Подобным способом можно расправиться и с другими вариантными типами (void* | void(*)() — это самые примитивные вариантные типы )
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
http://files.rsdn.org/4783/catsmiley.gif Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.