“+”操作符的使用技巧

描述

这篇写个平时易被忽略的小知识点,一元 + 操作符的使用技巧。

一般二元 + 操作符用得较多,只有一个操作数时,没人会多此一举地把 1 写成 +1。

不过若是操作数为整数或无作用域枚举类型,一元 + 操作符会执行 Integral promotion,此时会发生隐式转换。例如:

 

// unscoped enumeration
enum Enum : unsigned int {
    enum_val_a,
    enum_val_b,
    enum_val_c
};

int main() {

    bool b = true;
    +b; // int

    +enum_val_b; // unsigned int

    char c = 'c';
    +c; // int

    unsigned short s = 10;
    +s; // int

    int array[10];
    +array; // int*
}

 

若是你使用的 C++ 标准不支持 std::to_underlying,你可能得使用以下语句来达到同样目的:

 

static_cast>(enum_val_b);

 

这种写法太过繁琐,而以一元 + 操作符则可以非常简单地完成这种转换,当然前提须是 underlying 类型固定。

对于一些奇怪的类型,比如 std::uint8_t,它的类型是什么呢?顾名思义应该是 8-bit 的 Unsigned integer,然而实际上它是 unsigned char 的 typedef。那么在输出的时候就会遇到一些问题:

 

std::uint8_t u = 0x45;
std::cout << u; // E

 

最终输出将是 E,并不是一个无符号整数,你需要使用强制转换才能得到想要的输出。而借助一元 + 操作符,则可以非常简单地达到预期。

 

std::uint8_t u = 0x45;
std::cout << +u; // 69

 

另外,一元 + 操作符也支持指针类型的操作数,所以它也可以隐式地把 Lambda 转换为函数指针。例如:

 

auto fp = +[]{};
static_assert(std::is_same_v);

 

如果没有 +,那 fp 只是一个 closure 类型,断言出错。

另一个用法是在 Concepts 中,比如你想判断某类型当中是否存在某变量,可能会这样写:

 

template 
concept HasValue = requires(T t) {
    { T::num } -> std::integral;
};

struct S {
    int num;
};

// false
static_assert(HasValue);

 

没能达到预期是因为 T::num 是个 value,而非 type。一种做法是采用 std::is_integral,

 

template 
concept HasValue = requires(T t) {
    std::is_integral_v;
};

// true
static_assert(HasValue);

 

这种做法就将 T::num 变成了 type,同理也可以这样做:

 

template 
concept HasValue = requires(T t) {
    decltype(T::num){};
};

 

约束必须是表达式,是以无法只写类型。更简单的话可以这样写:

 

template 
concept HasValue = requires(T t) {
    T::num++;
};

 

因为自增运算符也可以构成表达式,那么最简单的做法就是采用一元 + 操作符。

 

template 
concept HasValue = requires(T t) {
    +T::num;
};

 

那么有没有办法可以禁止 Integral promotion 呢?Concepts 便有此妙用。看下面这个例子:

 

uint8_t bad_foo(uint8_t a, uint8_t b) {
    return a + b; // implicit conversion
}

std::same_as auto
good_foo(uint8_t a, uint8_t b) {
    return a + b; // Compile error!
}

 

对于 bad_foo(),return a + b 在不经意间发生了 Integral promotion,它其实相当于return uint8_t((int)a + (int)b)。

这种隐式转换的结果可能并不如人所愿,Concepts 相当于给返回值声明了 explict,从而避免错误。当你明确不需要返回值隐式转换的时候,可以借助这种方式。

活用这些小技巧,不仅可以简化代码,还能增加程序安全性。

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分