为什么以下代码在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;
}
答案 0 :(得分:33)
你可以删除c ++ 11中的函数
void foo(uint64_t) = delete;
它通过在函数重载分辨率下添加签名来工作,如果它是更好的匹配,则会发生错误。您也可以将其设为通用,仅允许原始签名
template <class T> void foo( T&& ) = delete;
答案 1 :(得分:9)
您也可以使用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
的重载,以及另一个处理其他任何内容的重载。
答案 2 :(得分:6)
这是一个允许扩大转换并防止缩小转换的解决方案:
#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;
}
答案 3 :(得分:5)
如果您想允许扩大转化次数,但禁止缩小转化次数,可能:
@media mobile and (min-width: 400px) {
.col { width:50% }
}
@media mobile and (max-width: 400px) {
.col { width:100% }
}
这会强制除void foo(uint16_t x) {
}
template <class T>
void foo( const T&& t )
{
return foo(uint16_t{t});
}
之外的所有类型都经过列表初始化,这会禁止缩小转换。
如果你已经有很多重载,它就不能很好地工作了。
答案 4 :(得分:4)
虽然这里的大多数答案在技术上都是正确的,但您很可能不希望该行为仅适用于此函数,因此您必须为每个转换案例编写的“代码级”解决方案可能不是您想要的
在“项目/编辑级别”,您可以添加此标记以警告您这些转换:
-Wconversion
或者如果您愿意直接将它们视为错误:
-Werror=conversion