[英]Prevent converting uint64_t to uint16_t
為什么以下代碼在clang ++中編譯?
是否有任何c ++標志來防止這種情況發生 - 我希望編譯器拋出錯誤,因為我將std :: uint64_t作為參數傳遞給接受std :: uint16_t的函數。
#include <cstdint>
using namespace std;
void foo(uint16_t x) {
}
int main() {
uint64_t x = 10000;
foo(x);
return 0;
}
你可以刪除c ++ 11中的函數
void foo(uint64_t) = delete;
它通過在函數重載分辨率下添加簽名來工作,如果它是更好的匹配,則會發生錯誤。 您也可以使其通用,只允許您原始簽名
template <class T> void foo( T&& ) = delete;
您還可以使用enable_if
作為SFINAE返回參數
#include <iostream>
#include <cstdint>
#include <type_traits>
template<typename T>
typename std::enable_if<std::is_same<T, uint16_t>::value>::type
foo(T x)
{
std::cout << "uint16_t" << std::endl;
}
template<typename T>
typename std::enable_if<!std::is_same<T, uint16_t>::value>::type
foo(T x)
{
std::cout << "rest" << std::endl;
}
int main() {
uint16_t x = 10000;
uint64_t y = 100000;
foo(x); // picks up uint16_t version
foo(y); // picks up anything else, but NOT uint16_t
return 0;
}
通過這種方式,您可以擁有一個專門處理uint16_t
重載,以及另一個處理其他任何uint16_t
重載。
這是一個允許擴大轉換並防止縮小轉換的解決方案:
#include <cstdint>
#include <type_traits>
void foo(uint16_t x) {
}
template <class T>
typename std::enable_if<sizeof(uint16_t) < sizeof(T)>::type foo(const T& t) = delete;
int main() {
uint64_t x = 10000;
uint16_t y = 10000;
uint8_t z = 100;
// foo(x); // ERROR: narrowing conversion
foo(y); // OK: no conversion
foo(z); // OK: widening conversion
return 0;
}
如果您還想禁止帶有簽名類型參數的調用(有符號和無符號類型之間的轉換不是“無損”),您可以使用以下聲明:
#include <cstdint>
#include <type_traits>
void foo(uint16_t x) {
}
template <class T>
typename std::enable_if<(sizeof(uint16_t) < sizeof(T)) ||
(std::is_signed<T>::value != std::is_signed<uint16_t>::value)
>::type
foo(const T& t) = delete;
int main() {
uint64_t u64 = 10000;
uint16_t u16 = 10000;
uint8_t u8 = 100;
int64_t s64 = 10000;
int16_t s16 = 10000;
int8_t s8 = 100;
//foo(u64); // ERROR: narrowing conversion
foo(u16); // OK: no conversion
foo(u8); // OK: widening conversion
//foo(s64); // ERROR: narrowing conversion AND signed/unsigned mismatch
//foo(s16); // ERROR: signed/unsigned mismatch
//foo(s8); // ERROR: signed/unsigned mismatch
return 0;
}
如果您想允許擴大轉化次數,但禁止縮小轉化次數,可能:
void foo(uint16_t x) {
}
template <class T>
void foo( const T&& t )
{
return foo(uint16_t{t});
}
這會強制除uint16_t
之外的所有類型都經過列表初始化,這禁止縮小轉換。
但是,如果你已經有很多重載,它就不能很好地工作。
雖然這里的大多數答案在技術上都是正確的,但您很可能不希望該行為僅適用於此函數,因此您必須為每個轉換案例編寫的“代碼級”解決方案可能不是您想要的。
在“項目/編譯級別”,您可以添加此標志以警告您這些轉換:
-Wconversion
或者如果您喜歡直接將它們視為錯誤:
-Werror=conversion
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.