2009-05-27 3 views
0

В основном, что я хочу сделать, в зависимости от какой-либо переменной, для перевода указателя пустоты в другой тип данных. Например (далее «отливать» переменная просто что-то, чтобы получить свою точку зрения):Кастовые указатели на пустоты, в зависимости от данных (C++)

void* ptr = some data; 
int temp = some data; 
int i = 0; 

... 

if(temp == 32)  cast = (uint32*) 
else if(temp == 16) cast = (uint16*) 
else    cast = (uint8*) 

i = someArray[*((cast)ptr)]; 

Есть ли в C++, который может сделать что-то вроде этого (так как вы не можете на самом деле присвоить переменную быть просто (uint32 *) или что-то подобное)? Прошу прощения, если это не ясно, любая помощь будет принята с большой благодарностью.

+0

Почему бы просто не сделать бросок во время теста? if (temp == 32) index = (uint32 *) ptr; // etc –

+0

Да, это очевидный путь, но если бы я сделал это так, мне понадобились бы сотни, если ... elses. if (temp == 32) i = someArray [* index32]; else if (temp == 16) i = someArray [* index16]; и т. д. Я надеялся, что есть простой способ сделать это, как указано выше. – Joel

+0

Вам все еще нужны сотни if/elses? –

ответ

5

"Правильный" способ:

union MyUnion 
{ 
    uint32 asUint32; 
    uint16 asUint16; 
    uint8 asUint8; 
} 

uint32 to_index(int size, MyUnion* ptr) 
{ 
    if (size== 32) return ptr->asUint32; 
    if (size== 16) return ptr->asUint16; 
    if (size== 8) return ptr->asUint8; 
} 

i = someArray[to_index(temp,ptr)] 

[обновление: фиксированный немой опечатка]

+0

Вы имеете в виду «размер», а не «темп» в трех условных выражениях? –

+0

Упс ... да ... исправлено. –

0

Похоже, что вы после объединения или используете Visual Studio _variant_t. Или может быть, typeinfo() будет полезен? (Честно говоря, я не совсем уверен, что вы пытаетесь сделать).

Что касается бросков, вы можете бросить практически что угодно - это то, что делает C++ опасным (и мощным, если вы действительно осторожны).

Также обратите внимание, что значения указателей являются 32-разрядными или 64-битными на большинстве платформ, поэтому вы не можете хранить uint64 в void * на 32-битной платформе.

Наконец, может быть, это то, что вы хотите:

void* p = whatever; 

uint32 x = (uint32)p; 

или, может быть

uint32 source = 6; 

void* p = &source; 

uint32 dest = *((uint32*)p); 

void* p = 
1

Очиститель решение:

uint32 to_index(int temp, void* ptr) { 
    if (temp == 32) return *((uint32*)ptr); 
    if (temp == 16) return *((uint16*)ptr); 
    if (temp == 8) return *((uint8*)ptr); 
    assert(0); 
} 

i = someArray[to_index(temp,ptr)] 
0

Если вы были заперты в использовании пустот PTR, и абсолютно необходимо для вызова [] с различными типами:

template <typename cast_to> 
inline 
int get_int_helper(someArray_t someArray, void* ptr) { 
    return someArray[*static_cast<cast_to*>(ptr)]; 
} 

int get_int(someArray_t someArray, void* ptr, int temp) { 
    switch (temp) { 
     case 32: return get_int_helper<uint32>(someArray,ptr); 
     case 16: return get_int_helper<uint16>(someArray,ptr); 
     default: return get_int_helper<uint8>(someArray,ptr); 
    } 
} 

Однако, как уже отмечалось, есть, вероятно, лучшие/другие способы сделать это. Скорее всего, любой массив, который у вас есть, не имеет множественного оператора [], поэтому ему не нужны разные типы. Кроме того, вы можете использовать boost :: variant для проведения различного объединения типов, чтобы вам не пришлось проходить вокруг temp

2

Очевидно, boost::variant - это путь. Он уже сохраняет тэг типа, который делает невозможным для вас использовать неверный тип, гарантируя это с помощью компилятора. Вот как это работает

typedef boost::variant<uint32_t*, uint16_t*, uint8_t*> v_type; 

// this will get a 32bit value, regardless of what is contained. Never overflows 
struct PromotingVisitor : boost::static_visitor<uint32_t> { 
    template<typename T> uint32_t operator()(T* t) const { return *t; } 
}; 

v_type v(some_ptr); // may be either of the three pointers 

// automatically figures out what pointer is stored, calls operator() with 
// the correct type, and returns the result as an uint32_t. 
int i = someArray[boost::apply_visitor(PromotingVisitor(), v)]; 
0

Кажется, вы хотите сохранить функцию «слепок», которая принимает недействительный * и производит целое число без знака. Таким образом, сделайте это функцией:

std::map<int, boost::function<unsigned(*)(void*)> casts; 
template <typename T> unsigned cast(void* v) { return *(T*)v; } 
casts[32] = cast<uint32>; 
casts[16] = cast<uint16>; 
casts[8] = cast<uint8>; 
casts[128] = MySpecialCastFromDouble; 

void* foo = getFoo(); 
unsigned bar = casts[16](foo);