2016-07-03 56 views
2

如果我將float號碼傳遞給期望int以下代碼的類,我希望得到編譯器錯誤。下面的代碼用gcc 4.9.3運行在編譯時使用模板驗證類型

gcc -std=c++98 -O0 -g3 -Wall -Wextra -c -fmessage-length=0 

我應該如何改變這樣它會返回編譯錯誤的情況下,不同類型中的類實例的類型和方法的輸入參數類型的代碼?

#include <iostream> 
template <typename T> 
class CheckValidity { 
    public: 
     CheckValidity(){}; 

     T isFoo(T variable) 
     { 
      T result = static_cast<T>(0); 
      if (variable > static_cast<T>(5)) 
      { 
       result = static_cast<T>(1); 
      } 
      return result; 
     }; 
}; 

int main() { 
    CheckValidity<int> checkValidityInt; 
    std::cout << checkValidityInt.isFoo(6.0f) << std::endl; 
    return 0; 
} 
+2

-std = C++ 98是一個很難的要求,或者你可以使用更高的標準嗎?某種'typename std :: enable_if'-magic應該可以做到這一點,但我不確定它是否可用於C++ 98。 – Kent

+0

@Kent,我可以使用,直到C++ 03標準。不幸的是,我的嵌入式編譯器不支持那麼多。 – Eagle

回答

2

你現在還沒有得到警告的原因是因爲float6.0f可以無損地轉換成int。也就是說,在轉換過程中不會失去任何精度,因爲6.0可以精確地表示爲6.編譯器知道這是因爲您正在使用編譯時常量。

如果你把它改成6.1f,例如,你應該得到一個警告(假設你已經-Wconversion啓用):

int main() { 
    CheckValidity<int> checkValidityInt; 
    std::cout << checkValidityInt.isFoo(6.1f) << std::endl; 
    return 0; 
} 
In function 'int main()': 
20 : warning: conversion to 'int' alters 'float' constant value [-Wfloat-conversion] 
std::cout << checkValidityInt.isFoo(6.1f) << std::endl; 

你也將得到一個警告,如果你傳遞的變量鍵入float,而不是一個常數。這意味着警告應該可以解決任何潛在的問題。一個常數的精確轉換不是一個真正的問題。

對此警告轉換爲錯誤(確保你不會錯過它),也通過-Werror標誌。

0

使成員函數模板成員函數。它爲處理不同類型打開了一些可能性。


使用static_assertstd::is_floating_point,以確保該功能沒有使用浮點類型調用。

template <typename U> 
T isFoo(U variable) 
{ 
    static_assert(std::is_floating_point<U>::value == false, 
        "Can't handle floating point types"); 
    T result = static_cast<T>(0); 
    if (variable > static_cast<T>(5)) 
    { 
     result = static_cast<T>(1); 
    } 
    return result; 
}; 

要確保UT是同一類型的,你可以使用std::is_same

template <typename U> 
T isFoo(U variable) 
{ 
    static_assert(std::is_same<T, U>::value, 
        "Can't handle different types"); 
    T result = static_cast<T>(0); 
    if (variable > static_cast<T>(5)) 
    { 
     result = static_cast<T>(1); 
    } 
    return result; 
}; 

爲了能夠應對U是的T派生類型,您可以使用:

template <typename U> 
T isFoo(U variable) 
{ 
    static_assert(std::is_base_of<T, U>::value, 
        "Can't handle incompatible types"); 
    T result = static_cast<T>(0); 
    if (variable > static_cast<T>(5)) 
    { 
     result = static_cast<T>(1); 
    } 
    return result; 
}; 
+0

@CodyGray,我發佈了答案後發現了錯誤。現在已經修復了。 –

2

對於C++ 98:

一種方式來實現你想要一個需要精確匹配的是什麼有哪些可以接受任何類型,但總是失敗,因爲SFINAE模板方法:

template<typename U> 
    U isFoo(U variable) 
    { 
     typename CheckValidity::InvalidType x; 
    } 

對於C++ 11:

您可以使用刪除方法以達到更清潔的效果相同:

template<typename U> 
    U isFoo(U variable) = delete; 
0

您CA n使用模板專業化:

//Returns false in the default case 
template<typename V> 
bool isFoo(V) 
{ 
    return false; 
}; 

//Returns true if the type passed is T 
template<> 
bool isFoo<T>(T) 
{ 
    return true; 
} 

該變量仍然作爲參數傳遞而沒有名稱,因爲您不需要它內部。它還被使用,因爲isFoo<decltype(var)>()isFoo(var)更好。


如果你可以使用C++ 11,使用 std::is_same或類似的結構:

//You need a separate type, because if you use T, you will just cast the result to T 
template<typename V> 
bool isFoo(V) 
{ 
    //Compare the types 
    return std::is_same<V, T>::value; 
}; 
0

這種效果是更好地實現,如果你只是離開剛剛宣佈通用模板類,但沒有定義和專門的模板類float的定義。我會嘗試玩類似列表...

0

這聽起來像你想要使用std::is_integral結合static_assert

在你想限制爲整數的任何功能或類模板,您可以撥打:

static_assert(std::is_integral<T>::value, "Integer required."); 

您可能也有興趣std::enable_if(或便民的typedef enable_if_t):

template <typename Integer, 
      typename = std::enable_if_t<std::is_integral<Integer>::value>> 

如果表達式爲假,您可以使用任何整數常量表達式調用static_assert來生成編譯時錯誤。您可以使用enable_if來限制可以實例化模板的類型(如果使用的是無效類型,也會導致編譯器錯誤)。

編輯:我只注意到你正在使用-std = C++ 98。如果你需要使用這個標準,我可以刪除這個答案。但是如果你可以使用C++ 11,這將比你在早期標準中做的更好。

+0

我的代碼應該在嵌入式系統上運行,這就是爲什麼我想避免任何類型的斷言 – Eagle

+1

爲什麼靜態斷言會成爲嵌入式系統的問題?他們絕對沒有運行時間成本,並且會在編譯時捕獲錯誤。看起來像你想要的嵌入式系統...... –

+0

請不要刪除你的答案。它可能(可能)對原始提問者沒有用(除非說服他進入這個千禧年),但對於搜索SO有類似問題的人可能會有用。 –