2014-12-20 87 views
2

我有這個類:讓一個函數用C返回任何類型++

#define TYPE_INVALID 0x00 
#define TYPE_BYTE 0x01 
#define TYPE_SHORT 0x02 
#define TYPE_INT  0x03 
#define TYPE_LONG 0x04 
#define TYPE_FLOAT 0x05 
#define TYPE_DOUBLE 0x06 

class BASIC_TYPE 
{ 
    private: 
     int8_t type; 
     int8_t byteValue; 
     int16_t shortValue; 
     int32_t intValue; 
     int64_t longValue; 
     float floatValue; 
     double doubleValue; 

    public: 
     BASIC_TYPE(); 
     template<typename T> BASIC_TYPE(int8_t, T); 

     template<typename T> void set(T); 
     template<typename T> T get(); 
}; 

BASIC_TYPE::BASIC_TYPE() 
{ 
    type = TYPE_INVALID; 
} 

template<typename T> BASIC_TYPE::BASIC_TYPE(int8_t newType, T value) 
{ 
    type = newType; 
    set(value); 
} 

template<typename T> void BASIC_TYPE::set(T value) 
{ 
    switch(type) 
    { 
     case TYPE_BYTE : byteValue = value; break; 
     case TYPE_SHORT : shortValue = value; break; 
     case TYPE_INT : intValue = value; break; 
     case TYPE_LONG : longValue = value; break; 
     case TYPE_FLOAT : floatValue = value; break; 
     case TYPE_DOUBLE : doubleValue = value; break; 
    } 
} 

template<typename T> T BASIC_TYPE::get() 
{ 
    switch(type) 
    { 
     case TYPE_BYTE : return byteValue; 
     case TYPE_SHORT : return shortValue; 
     case TYPE_INT : return intValue; 
     case TYPE_LONG : return longValue; 
     case TYPE_FLOAT : return floatValue; 
     case TYPE_DOUBLE : return doubleValue; 
    } 
} 

現在我想使用get() - 函數輸出存儲的號碼是這樣的:

BASIC_TYPE val1(TYPE_INT, 1234); 
BASIC_TYPE val2(TYPE_DOUBLE, 3.1415926535); 

val1.set(5678); 
val2.set(2.7182818284); 
printf("%d\n%f\n", val1.get(), val2.get()); 

但是g ++說no matching function call to 'BASIC_TYPE::get()printf功能和那template argument deduction/substitution failedcouldn't deduce template parameter 'T')。

需要更改哪些代碼才能正確編譯代碼?

+2

你剛剛重新'boost :: any'? –

+3

對於工會中的所有類型的私人成員,這將會更有效率的記憶 – galinette

+1

@KerrekSB:在某些情況下,具有提升依賴性不是一個好主意。 – galinette

回答

6

「爲了讓代碼正確編譯,需要改變什麼?」

在這種情況下,您需要明確。只要寫

printf("%d\n%f\n", val1.get<int>(), val2.get<double>()); 
         // ^^^^^   ^^^^^^^^ 

C++不能僅僅通過返回類型(其他,因爲它可以與set()其中T顯示爲參數類型)區分各種get()功能實例。
在這種情況下,您需要指定類型來明確地實例化模板化函數(如上所示)。


另外請注意:我寧願使用enum,而不是那些#define TYPE_xxx聲明:

enum MySupportedTypes { 
    TYPE_INVALID , 
    TYPE_BYTE , 
    TYPE_SHORT , 
    TYPE_INT  , 
    TYPE_LONG , 
    TYPE_FLOAT , 
    TYPE_DOUBLE , 
}; 

爲了您get()模板功能的實現,你應該考慮這樣的事情,以避免get()函數被調用不適當的請求類型。

template<typename T> T BASIC_TYPE::get() { 
    switch(type) { 
     case TYPE_BYTE: 
      std::is_same<T,int8_t> ? return byteValue : throw std::bad_typeid; 
     case TYPE_SHORT: 
      std::is_same<T,int16_t> ? return shortValue : throw std::bad_typeid; 
     // analogous ... 
    } 
} 

或者甚至更好的提供一種機制,可以在編譯時捕獲類型不匹配。


1)見std::is_same

+0

想知道爲什麼OP沒有聲明類型T的類成員,並將值存儲在那裏 –

+0

我有一種感覺,OP希望'val' *記住*其成員類型當前處於活動狀態並返回該成員類型,但是我正在猜測。 –

+0

@giorgim你可以使用靜態綁定這種東西。我們在嵌入式固件中使用這些東西。讓它正常工作會更復雜一點,並且確保錯誤選擇類型的編譯時錯誤。 –

0

您想在返回類型,其中C++並沒有真正讓你做很容易超載的文檔參考。然而,我會指出,最後一個例子需要你告訴它你想要的類型,因爲參數可以是任何類型。即使C++讓你按返回類型重載,它仍然不知道你想要什麼類型。

這就是說,有一個醜陋的技巧可以用來重載返回類型。我學會了它可用於這一點的同時尋找到如何通過返回類型,這裏超載:Function overloading by return type?

看哪:

class BASIC_TYPE 
{ 
    // Your stuff, then: 
    operator int(){ if (type != TYPE_INT) throw std::bad_typeid; return intValue; } 
    operator float(){ if (type != TYPE_FLOAT) throw std::bad_typeid; return floatValue; } 
    // And so on for every supported type 
} 

有了這個,你甚至不需要一個get函數,你可以請撥打該值本身:

BASIC_TYPE val1(TYPE_INT, 1234); 

//float bad = val1; // throws bad_typeid 
int good = val1; // sets good to 1234 

您可以使用強制轉換來獲得特定的一個,以防萬一您將轉換爲錯誤的類型。

如果重載構造函數和賦值運算符,你甚至可以擺脫難看的語法,你有宣告類型:

class BASIC_TYPE 
{ 
    public: 
     // Constructors 
     BASIC_TYPE(int i):type(TYPE_INT),intValue(i){} 
     // So on for the other types 
     // Assignment 
     BASIC_TYPE & operator=(int i){ if (type != TYPE_INT) throw std::bad_typeid; intValue = i; return *this;} 
} 

BASIC_TYPE intType (1234); // TYPE_INT chosen autmatically 
// intType = 1.0; // throws 
intType = 4321; 
0

沒有必要存儲六種不同類型的六種不同的數據成員。他們可以合併成一個工會。也可以使用模板元編程設置type標誌。不需要在構造函數中明確地這樣做。在使用聯合時,必須確保get函數的模板參數與對象的實際類型相匹配。在這種情況下,我選擇僅返回模板參數類型的零初始化值,如果該類型不匹配對象的類型。您可以選擇拋出異常。

#include <iostream> 
#include <type_traits> 

#define TYPE_INVALID 0x00 
#define TYPE_BYTE 0x01 
#define TYPE_SHORT 0x02 
#define TYPE_INT  0x03 
#define TYPE_LONG 0x04 
#define TYPE_FLOAT 0x05 
#define TYPE_DOUBLE 0x06 

using namespace std; 

class BASIC_TYPE 
{ 
    private: 
     int8_t type; 
     union 
     { 
      int8_t byteValue; 
      int16_t shortValue; 
      int32_t intValue; 
      int64_t longValue; 
      float floatValue; 
      double doubleValue; 
     } 
     data; 

    public: 
     BASIC_TYPE(); 
     template<typename T> BASIC_TYPE(T); 
     template<typename T> void set(T); 
     template<typename T> T get(); 
}; 

BASIC_TYPE::BASIC_TYPE() 
{ 
    type = TYPE_INVALID; 
} 

template<typename T> BASIC_TYPE::BASIC_TYPE(T value) 
{ 
    set(value); 
} 

template<typename T> void BASIC_TYPE::set(T value) 
{ 
    if (is_same<T, int8_t>::value) 
    { 
     type = TYPE_BYTE; 
     data.byteValue = value; 
    } 
    else if (is_same<T, int16_t>::value) 
    { 
     type = TYPE_SHORT; 
     data.shortValue = value; 
    } 
    else if (is_same<T, int32_t>::value) 
    { 
     type = TYPE_INT; 
     data.intValue = value; 
    } 
    else if (is_same<T, int64_t>::value) 
    { 
     type = TYPE_LONG; 
     data.longValue = value; 
    } 
    else if (is_same<T, float>::value) 
    { 
     type = TYPE_FLOAT; 
     data.floatValue = value; 
    } 
    else if (is_same<T, double>::value) 
    { 
     type = TYPE_DOUBLE; 
     data.doubleValue = value; 
    } 
    else 
     type = TYPE_INVALID; 

} 

template<typename T> T BASIC_TYPE::get() 
{ 
    T ret{}; 
    if (type == TYPE_BYTE && is_same<T, int8_t>::value) 
     ret = data.byteValue; 
    else if (type == TYPE_SHORT && is_same<T, int16_t>::value) 
     ret = data.shortValue; 
    else if (type == TYPE_INT && is_same<T, int32_t>::value) 
     ret = data.intValue; 
    else if (type == TYPE_LONG && is_same<T, int64_t>::value) 
     ret = data.longValue; 
    else if (type == TYPE_FLOAT && is_same<T, float>::value) 
     ret = data.floatValue; 
    else if (type == TYPE_DOUBLE && is_same<T, double>::value) 
     ret = data.doubleValue; 

    return ret; 
}