2015-02-23 115 views
2

this answer我真正想要做的是在我的模板參數中定義一個typename,該模板參數可用於鑄造返回。模板中的enable_if參數創建模板重定義錯誤

所以這樣的:

template <typename T> 
typename std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type caster(T value){ return reinterpret_cast<unsigned char&>(value); } 

會變成這樣:

template <typename T, typename R = std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type > 
R caster(T value){ return reinterpret_cast<R&>(value); } 

這工作,並根據需要爲一個模板專業化的行爲,但說我再添專業化:

template <typename T, typename R = std::enable_if<sizeof(short) == sizeof(T), short>::type> 
R caster(T value){ return reinterpret_cast<R&>(value); } 

現在我收到一個錯誤:

error C2995: 'R caster(T)' : function template has already been defined

有沒有辦法讓編譯器相信,只有這些專門化中的一個專門針對任何給定的調用實際構建?

回答

0

看來,最好的解決辦法在這裏可能是使用的conditional秒的轉換,這會阻止我,從具有模板專門愚弄:

template <typename T, typename R = std::conditional<sizeof(T) == sizeof(unsigned char), 
                unsigned char, 
                conditional<sizeof(T) == sizeof(unsigned short), 
                   unsigned short, 
                   conditional<sizeof(T) == sizeof(unsigned long), 
                      unsigned long, 
                      enable_if<sizeof(T) == sizeof(unsigned long long), unsigned long long>::type>::type>::type>::type> 
R caster(T value){ return reinterpret_cast<R&>(value); } 

我向讀者致歉就像讀取嵌套三元組一樣。不過,我目前還沒有意識到處理這個問題的更簡潔的方法。

這很遺憾,仍然不能阻止用戶通過提供他自己的第二個模板參數(如hvd所述)來跺腳我的所有違約。

編輯:

我問它具有不需要放置typename在模板定義不需要聲明類型兩次解決方案的另一個問題here

1

不,沒有。模板默認參數就是這樣,默認爲。任何用戶都可以撥打caster<short, short>,這會匹配兩個重載。

但是,可以添加更多僞參數。

template <typename T, 
      typename R = typename std::enable_if<sizeof(unsigned char) == sizeof(T), unsigned char>::type > 
R caster(T value) { return reinterpret_cast<R&>(value); } 

template <typename T, 
      typename R = typename std::enable_if<sizeof(short) == sizeof(T), short>::type, 
      typename = void> 
R caster(T value) { return reinterpret_cast<R&>(value); } 

(還要注意添加typename。)


然而,由於所有機構是相同的,我可能不會有過載走。

template <std::size_t N> 
struct cast_result; 

template <> 
struct cast_result<sizeof(std::uint8_t)> { 
    typedef std::uint8_t type; 
}; 

template <> 
struct cast_result<sizeof(std::uint16_t)> { 
    typedef std::uint16_t type; 
}; 

... 

template <typename T, typename R = typename cast_result<sizeof(T)>::type> 
R caster(T value) { 
    return reinterpret_cast<R&>(value); 
} 

最後一點:這種使用reinterpret_cast是違反了別名規則。然而,這是很容易固定:

template <typename T, typename R = typename cast_result<sizeof(T)>::type> 
R caster(T value) { 
    R result; 
    std::memcpy(&result, &value, sizeof result); 
    return result; 
} 
+0

啊,至少我明白爲什麼現在沒有建設。好像我可以設置一個'typedef'或者一些不是用戶參數的東西,但會定義使用的類型。 – 2015-02-23 13:56:52

+0

我在'reinterpret_cast'上看不到任何錯誤?對我來說,它應該按原樣工作。如果位數相同,那麼將另一個視爲另一個應該不會有問題? – 2015-02-23 20:54:50

+0

@JonathanMee語言本來可以被定義,但不是。該標準包含:「如果程序試圖通過以下類型之一的glvalue訪問對象的存儲值,則行爲未定義:」後跟一個列表,該列表不包含特定大小的對象的任何註釋。一些編譯器(如GCC)使用該規則來積極優化代碼,注意到例如給定'int * a'和'long * b',存儲爲'* a'並從'* b'讀取的代碼,編譯器可以重新排序訪問,因爲指針不允許指向同一個對象。 – hvd 2015-02-23 21:07:50