考慮這段代碼:
template <typename T>
T abs(const T& n)
{
if (!std::is_signed<T>::value)
throw logic_error;
if (n < 0)
return -n;
return n;
}
我想完全禁止將我的函式與unsigned變數一起使用,因為它沒有意義,而且可能用戶甚至不知道他使用了一個unsigned變數。例如,我可以在某種程度上避免這個問題:
template <typename T>
T abs(const T& n)
{
if constexpr(!std::is_signed<T>::value)
n = "";
if (n < 0)
return -n;
return n;
}
但是如果我呼叫abs(4u),編譯器錯誤不是很明顯。類似的東西"can't apply = const char[1] to double"。我可以讓它更明顯嗎?或者只是進行多次多載?
uj5u.com熱心網友回復:
#include <type_traits>
template <typename T>
T abs(T n)
{
static_assert(std::is_signed<T>::value, "Type must be signed.");
if (n < 0) { return -n; }
return n;
}
int main()
{
return abs(3u);
}
uj5u.com熱心網友回復:
1. 概念
從 C 20 開始,您可以為此使用概念。
如果你對整數引數沒問題,你可以使用std::signed_integral:
#include <concepts>
template <std::signed_integral T>
T abs(const T& n)
{
if (n < 0)
return -n;
return n;
}
如果您還想允許double等...您必須制定自己的概念:
template<class T>
concept signed_value = std::is_signed_v<T>;
template <signed_value T>
T abs(const T& n)
{
if (n < 0)
return -n;
return n;
}
如果您嘗試使用無符號型別,則會導致這樣的編譯器錯誤:
error: no matching function for call to 'abs(unsigned int&)'
note: candidate: 'template<class T> requires signed_integral<T> T abs(const T&)'
這很清楚,abs()只接受來自簽名的簽名型別。
2. SFINAE
如果 C 20 不可用,您可以使用 SFINAE,盡管您得到的錯誤訊息非常神秘:
template <class T>
std::enable_if_t<std::is_signed_v<T>, T> abs(const T& n)
{
std::cout << "HELLO" << std::endl;
if (n < 0)
return -n;
return n;
}
但這會導致如下錯誤訊息:
error: no matching function for call to 'abs(unsigned int&)'
note: candidate: 'template<class T> std::enable_if_t<is_signed_v<T>, T> abs(const T&)'
note: template argument deduction/substitution failed:
In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = unsigned int]':
required by substitution of 'template<class T> std::enable_if_t<is_signed_v<T>, T> abs2(const T&) [with T = unsigned int]'
因此,您需要對 SFINAE 錯誤感到滿意。
3.好老 static_assert
或者,您也可以將 a 添加static_assert到您的函式中。
這在宣告中根本不可見,只在函式的定義中可見。
template <class T>
T abs(const T& n)
{
static_assert(std::is_signed_v<T>, "T must be signed!");
if (n < 0)
return -n;
return n;
}
4.使用 std::abs()
C 已經提供了一種std::abs()為您處理所有潛在邊緣情況的實作,因此如果可以,我建議您改用該實作。
如果您傳入給定 int 型別的最小值,您的代碼還包含一個潛在的錯誤,例如INT_MIN.
- 一個 32bit int 可以表示的最小值是 -2147483648
- 但它所能代表的最大只有2147483647
因此,以abs()最小值呼叫您的函式,例如abs(-2147483648)會導致未定義的行為(std::abs()具有相同的行為,但仍然值得指出)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/375295.html
上一篇:類層次結構虛擬方法的CRTP引數
下一篇:輸入引數的型別取決于模板布林值
