2012-05-14 48 views
6

注意:這與Determine number of bits in integral type at compile time非常相似,但是這是一個非常簡單的版本,在一個.cpp像msg(long)``和候選`msg(int32_t)`和`msg(int64_t)``

編輯:增加了一個解決方案 - 雖然正確解釋給出(並接受),我發現了一種一般解決問題。

問題

問題是與功能類似於

msg(int32_t); 
msg(int64_t); 

long long myLong = 6; 
msg(myLong); // Won't compile on gcc (4.6.3), call is ambiguous 

電話本上編譯MSVC。任何人都可以提供一個解釋爲什麼在gcc上失敗(我假設它可能與gcc通常嚴格符合標準的事實有關)以及如何正確實現相同效果的示例?

#include <iostream> 
#include <stdint.h> 

#include <boost/integer.hpp> 

using namespace std; 

void msg(int v) { cout << "int: " << sizeof(int) << ' ' << v << '\n'; } 
void msg(long v) { cout << "long: " << sizeof(long) << ' ' << v << '\n'; } 
void msg(long long v) { cout << "long long: " << sizeof(long long) << ' ' << v << '\n'; } 

void msg2(int32_t v) { cout << "int32_t: " << sizeof(int32_t) << ' ' << v << '\n'; } 
void msg2(int64_t v) { cout << "int64_t: " << sizeof(int64_t) << ' ' << v << '\n'; } 
void msg2(uint32_t v) { cout << "uint32_t: " << sizeof(uint32_t) << ' ' << v << '\n'; } 
void msg2(uint64_t v) { cout << "uint64_t: " << sizeof(uint64_t) << ' ' << v << '\n'; } 


int main() 
{ 

    int myInt = -5; 
    long myLong = -6L; 
    long long myLongLong = -7LL; 

    unsigned int myUInt = 5; 
    unsigned int myULong = 6L; 
    unsigned long long myULongLong = 7LL; 

    msg(myInt); 
    msg(myLong); 
    msg(myLongLong); 

    msg2(myInt); 
    msg2(myLong);  // fails on gcc 4.6.3 (32 bit) 
    msg2(myLongLong); 

    msg2(myUInt); 
    msg2(myULong); // fails on gcc 4.6.3 (32 bit) 
    msg2(myULongLong); 

    return 0; 
} 

// Output from MSVC (and gcc if you omit lines that would be commented out) 
int: 4 5 
long: 4 6 
long long: 8 7 
int32_t: 4 -5 
int32_t: 4 -6 // omitted on gcc 
int64_t: 8 -7 
uint32_t: 4 5 
uint32_t: 4 6 // omitted on gcc 
uint64_t: 8 7 

的解決方案是提供一種成功映射intlonglong long到適當int32_tint64_t的功能。這可以在運行時通過if (sizeof(int)==sizeof(int32_t))類型語句輕鬆完成,但編譯時解決方案更可取。編譯時解決方案可通過使用boost::enable_if獲得。

下面的工作在MSVC10和gcc 4.6.3。 解決方案可以通過禁用非整數類型來進一步增強,但這超出了這個問題的範圍。

#include <iostream> 
#include <stdint.h> 

#include <boost/integer.hpp> 
#include <boost/utility/enable_if.hpp> 
#include <boost/type_traits/is_signed.hpp> 
#include <boost/type_traits/is_unsigned.hpp> 

using namespace std; 

template <class InputT> 
typename boost::enable_if_c<sizeof(InputT)==sizeof(int32_t) && boost::is_signed<InputT>::value, 
int32_t>::type ConvertIntegral(InputT z) { return static_cast<int32_t>(z); } 

template <class InputT> 
typename boost::enable_if_c<sizeof(InputT)==sizeof(int64_t) && boost::is_signed<InputT>::value, 
int64_t>::type ConvertIntegral(InputT z) { return static_cast<int64_t>(z); } 

template <class InputT> 
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint32_t) && boost::is_unsigned<InputT>::value, 
uint32_t>::type ConvertIntegral(InputT z) { return static_cast<uint32_t>(z); } 

template <class InputT> 
typename boost::enable_if_c<sizeof(InputT)==sizeof(uint64_t) && boost::is_unsigned<InputT>::value, 
uint64_t>::type ConvertIntegral(InputT z) { return static_cast<uint64_t>(z); } 

void msg(int v) { cout << "int: " << sizeof(int) << ' ' << v << '\n'; } 
void msg(long v) { cout << "long: " << sizeof(long) << ' ' << v << '\n'; } 
void msg(long long v) { cout << "long long: " << sizeof(long long) << ' ' << v << '\n'; } 


void msg2(int32_t v) { cout << "int32_t: " << sizeof(int32_t) << ' ' << v << '\n'; } 
void msg2(int64_t v) { cout << "int64_t: " << sizeof(int64_t) << ' ' << v << '\n'; } 
void msg2(uint32_t v) { cout << "uint32_t: " << sizeof(uint32_t) << ' ' << v << '\n'; } 
void msg2(uint64_t v) { cout << "uint64_t: " << sizeof(uint64_t) << ' ' << v << '\n'; } 

int main() 
{ 

    int myInt = -5; 
    long myLong = -6L; 
    long long myLongLong = -7LL; 

    unsigned int myUInt = 5; 
    unsigned int myULong = 6L; 
    unsigned long long myULongLong = 7LL; 

    msg(myInt); 
    msg(myLong); 
    msg(myLongLong); 

    msg2(ConvertIntegral(myInt)); 
    msg2(ConvertIntegral(myLong)); 
    msg2(ConvertIntegral(myLongLong)); 

    msg2(ConvertIntegral(myUInt)); 
    msg2(ConvertIntegral(myULong)); 
    msg2(ConvertIntegral(myULongLong)); 

    return 0; 
} 
+0

MSVC有'typedef _Longlong int64_t'和gcc有'typedef long long int int64_t',所以我認爲這兩種情況下的類型是一樣的。無論如何,這是使用_long_的調用是問題... – Zero

回答

2

Greg擊中了頭部上的指甲:int32_tint64_t是typedef,可能是也可能不是long。如果兩者都不是long的typedef,則重載解析可能失敗。 long->int32_tlong->int64_t都有Rank = Promotion(表12,13.3.3.1.2)

3

代碼是否會編譯是實現定義的。沒有類型int32_tint64_t;這些僅僅是對現有整型的typedef。如果這種類型碰巧已經超載(int,longlong long),這幾乎可以肯定是這種情況,那麼您可以有多個相同函數的定義。如果它們在同一個翻譯單元中,則這是編譯時錯誤,需要診斷。如果他們在不同的翻譯單位,它是未定義的行爲,但我想大多數實現也會產生一個錯誤。

就你而言,最好的解決方案可能是製作一個模板msg,並將該類型的名稱作爲參數傳遞。

+1

int32_t和int64_t是同一類型嗎?不應該有其他兩位(如測試代碼的輸出中所示)?無論如何,gcc具有'typedef int int32_t'和'typedef long long int int64_t',所以它們在這種特殊情況下是不一樣的,即使它們在某些其他體系結構上可能是相同的。 – Zero

+4

相同功能沒有多個定義。只有當'int32_t'與'int64_t'相同時 - 這是不可能的。 這裏的實際問題是,在32位平臺上的gcc中,'int32_t'和'int64_t'都不是'long'的typedef(第一個是'int',第二個是'long long')。這就是爲什麼當你嘗試調用msg(long)時,它是模糊的 – Greg

+1

@Greg是的。我錯過了這個功能有不同名稱的事實,這當然會改變一切。 (或者不這樣做,因爲正如你指出的那樣,'int32_t'和'int64_t'的確切類型是實現定義的,而且由於有三個調用'msg2',有三種不同的類型,至少有一個不會是一個精確的匹配,並且取決於實際的typedef,可能不明確。 –

相關問題