【一分钟学C++】const和constexpr

在这里插入图片描述

竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~
公众号: C++学习与探索  |  个人主页: rainInSunny  |  个人专栏: Learn OpenGL In Qt

文章目录

const

  const 在 C++ 中表示常量,但是这里的常量不区分编译时常量和运行时常量,可以理解为 read-only 的语意。一般来说使用 const 是为了防止值被修改:

const int x = 100; // 常量
const int& rx = x; // 常量引用
const int* px = &x;// 常量指针
int* const px = &x;// 指针常量
const int* const px = &x; // 指向常量的指针常量

  const 可以用来修饰变量、引用和指针,修饰指针又区分为常量指针指针常量。给变量加上 const 之后变量”就成了“常量”,只能读、禁止写,编译器会帮你检查出所有对它的写操作,发出警告,在编译阶段防止有意或者无意的修改。这样一来,const 常量用起来就相对安全一点。所以在设计函数的时候,将参数用 const 修饰的话,一个是可以保证效率,另一个是保证安全,是属于防御编程的一种形式。另外修饰指针时,下面的情况应该是等价的:

  • const int * == int const *
  • const int * const == int const * const

  除此之外,const 还能声明在成员函数上,const 被放在了函数的后面,表示这个函数是一个“常量”,函数的执行过程是 const 的,不会修改对象的状态(即成员变量)。比如:

class constTest
{
private:
    const int MAX_COUNT = 256; // const成员变量
    int m_memberValue; // 成员变量
public:
    int getValue() const // 用于获取值,不应该改变成员变量的值,所以加上const
    {
        // error: assignment of member constTest::m_memberValue 
        // in read-only object
        m_memberValue = 100;
        return m_memberValue;
    }
};

  经常会遇到一个问题“const 和 volatile 关键字能否作用于同一个变量?”。首先结论是可以的,针对这两个关键字有以下说明:

  • const 修饰的变量用于限定程序内不允许修改。
  • volatile 用于提示编译器修饰的变量可能会被意外的改变,防止编译器进行优化,强调每次访问修饰的变量时都需要从内存中读取该值。

  例如一个在共享内存上的变量 const volatile int sharedNum = 10;,既不希望程序内部对它进行改变,而该变量又存在被其它程序改变的可能性,这时就需要同时使用 const 和 volatile。

constexpr

  constexpr 是在 C++ 11 被引进的,它的字面意思是 constant expression,常量表达式。它可以作用在变量和函数上。一个 constexpr 变量是一个编译时完全确定的常数。一个 constexpr 函数至少对于某一组实参可以在编译期间产生一个编译期常数。它和 const 区别如下:

  • const 不区分编译期常量和运行时常量,仅仅保证修饰变量的只读语意。
  • constexpr 修饰变量则表明这个变量在编译期就能计算出确定的值。在 C++ 11 引入 constexpr 后,相当于承担了 const 表示常量的责任,这样 const 就单纯表示只读的语意就好。

  另外当 constexpr 修饰指针类型的时候,它仅仅会添加顶层 const,可以看下面例子:

// 这里如果不考虑编译期还是运行时常量,等价于 char * const msg = "test!"
static constexpr char *msg = "test!";

// 需要手动补上底层 const 限定 msg 指向的对象不允许被修改
static constexpr const char *msg = "test!";

  可以看出 constexpr 修饰指针的时候添加的 const 是顶层 const,也就是这个 const 是作用在指针上,表示指针指向的地址不允许被修改,而可以通过该指针修改指向的值,显然这里修改字符串字面量的值会产生未定义的行为。所以需要像下面这样额外加上一个 const 限定 msg 指向的值不允许被修改。

  还有一种情况是 constexpr 修饰函数:

#include <iostream>
#include <array>
using namespace std;

constexpr int getNum(int i)
{
    return i + 5;
}

int main()
{
    int i = 2;
    std::array<int, getNum(3)> arr; // OK
    getNum(i); // Call is OK
    std::array<int, getNum(i)> arr1; // Error
   
}

  上面代码中,getNum() 返回值被 constexpr 修饰,但是并不保证它的返回值就一定在编译期确定,如果出现在编译期无法确定的情况,constexpr 修饰的函数等同于一个普通函数。例如 main 函数中的 getNum(5) 可以在编译期确定返回值,但是 getNum(i) 无法在编译期确定返回值。getNum(i) 可以正常调用,和普通函数一样,但是不能作为 std::array<int, getNum(i)> 的参数,因为该参数需要编译期常量。
  另外,被 constexpr 修饰的函数具有隐式内联的特点。

a.cpp: In member function ‘long int Date::totalDaysSinceEpoch() const’: a.cpp:57:33: error: no matching function for call to ‘Date::isLeapYear(int&) const’ 57 | total += (isLeapYear(i) ? 366 : 365); | ~~~~~~~~~~^~~ a.cpp:46:10: note: candidate: ‘bool Date::isLeapYear() const’ 46 | bool isLeapYear() const { | ^~~~~~~~~~ a.cpp:46:10: note: candidate expects 0 arguments, 1 provided a.cpp: In instantiation of ‘T maxn(T*, int) [with T = Time]’: a.cpp:118:46: required from here a.cpp:100:18: error: no match for ‘operator>’ (operand types are ‘Time’ and ‘Time’) 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/bits/stl_algobase.h:67, from /usr/include/c++/11/bits/char_traits.h:39, from /usr/include/c++/11/ios:40, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/bits/stl_iterator.h:538:5: note: candidate: ‘template<class _IteratorL, class _IteratorR> requires three_way_comparable_with<_IteratorR, _IteratorL, std::partial_ordering> constexpr std::compare_three_way_result_t<_IteratorL, _IteratorR> std::operator<=>(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&)’ (reversed) 538 | operator<=>(const reverse_iterator<_IteratorL>& __x, | ^~~~~~~~ /usr/include/c++/11/bits/stl_iterator.h:538:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘const std::reverse_iterator<_IteratorL>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/bits/stl_algobase.h:67, from /usr/include/c++/11/bits/char_traits.h:39, from /usr/include/c++/11/ios:40, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/bits/stl_iterator.h:1596:5: note: candidate: ‘template<class _IteratorL, class _IteratorR> requires three_way_comparable_with<_IteratorR, _IteratorL, std::partial_ordering> constexpr std::compare_three_way_result_t<_IteratorL, _IteratorR> std::operator<=>(const std::move_iterator<_IteratorL>&, const std::move_iterator<_IteratorR>&)’ (reversed) 1596 | operator<=>(const move_iterator<_IteratorL>& __x, | ^~~~~~~~ /usr/include/c++/11/bits/stl_iterator.h:1596:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘const std::move_iterator<_IteratorL>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/bits/basic_string.h:48, from /usr/include/c++/11/string:55, from /usr/include/c++/11/bits/locale_classes.h:40, from /usr/include/c++/11/bits/ios_base.h:41, from /usr/include/c++/11/ios:42, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/string_view:556:5: note: candidate: ‘template<class _CharT, class _Traits> constexpr decltype (__char_traits_cmp_cat<_Traits>(0)) std::operator<=>(std::basic_string_view<_CharT, _Traits>, std::__type_identity_t<std::basic_string_view<_CharT, _Traits> >)’ (reversed) 556 | operator<=>(basic_string_view<_CharT, _Traits> __x, | ^~~~~~~~ /usr/include/c++/11/string_view:556:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘std::basic_string_view<_CharT, _Traits>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/string:55, from /usr/include/c++/11/bits/locale_classes.h:40, from /usr/include/c++/11/bits/ios_base.h:41, from /usr/include/c++/11/ios:42, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/bits/basic_string.h:6276:5: note: candidate: ‘template<class _CharT, class _Traits, class _Alloc> decltype (__char_traits_cmp_cat<_Traits>(0)) std::operator<=>(const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&, const _CharT*)’ (reversed) 6276 | operator<=>(const basic_string<_CharT, _Traits, _Alloc>& __lhs, | ^~~~~~~~ /usr/include/c++/11/bits/basic_string.h:6276:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/bits/stl_algobase.h:64, from /usr/include/c++/11/bits/char_traits.h:39, from /usr/include/c++/11/ios:40, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/bits/stl_pair.h:473:5: note: candidate: ‘template<class _T1, class _T2> constexpr std::common_comparison_category_t<decltype (std::__detail::__synth3way(declval<_T1&>(), declval<_T1&>())), decltype (std::__detail::__synth3way(declval<_T2&>(), declval<_T2&>()))> std::operator<=>(const std::pair<_T1, _T2>&, const std::pair<_T1, _T2>&)’ (rewritten) 473 | operator<=>(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) | ^~~~~~~~ /usr/include/c++/11/bits/stl_pair.h:473:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘const std::pair<_T1, _T2>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/bits/stl_algobase.h:67, from /usr/include/c++/11/bits/char_traits.h:39, from /usr/include/c++/11/ios:40, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/bits/stl_iterator.h:554:5: note: candidate: ‘template<class _Iterator> requires three_way_comparable<_Iterator, std::partial_ordering> constexpr std::compare_three_way_result_t<_Iterator, _Iterator> std::operator<=>(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorL>&)’ (rewritten) 554 | operator<=>(const reverse_iterator<_Iterator>& __x, | ^~~~~~~~ /usr/include/c++/11/bits/stl_iterator.h:554:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘const std::reverse_iterator<_IteratorL>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/bits/stl_algobase.h:67, from /usr/include/c++/11/bits/char_traits.h:39, from /usr/include/c++/11/ios:40, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/bits/stl_iterator.h:1655:5: note: candidate: ‘template<class _Iterator> requires three_way_comparable<_Iterator, std::partial_ordering> constexpr std::compare_three_way_result_t<_Iterator, _Iterator> std::operator<=>(const std::move_iterator<_IteratorL>&, const std::move_iterator<_IteratorL>&)’ (rewritten) 1655 | operator<=>(const move_iterator<_Iterator>& __x, | ^~~~~~~~ /usr/include/c++/11/bits/stl_iterator.h:1655:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘const std::move_iterator<_IteratorL>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/bits/basic_string.h:48, from /usr/include/c++/11/string:55, from /usr/include/c++/11/bits/locale_classes.h:40, from /usr/include/c++/11/bits/ios_base.h:41, from /usr/include/c++/11/ios:42, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/string_view:549:5: note: candidate: ‘template<class _CharT, class _Traits> constexpr decltype (__char_traits_cmp_cat<_Traits>(0)) std::operator<=>(std::basic_string_view<_CharT, _Traits>, std::basic_string_view<_CharT, _Traits>)’ (rewritten) 549 | operator<=>(basic_string_view<_CharT, _Traits> __x, | ^~~~~~~~ /usr/include/c++/11/string_view:549:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘std::basic_string_view<_CharT, _Traits>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/string:55, from /usr/include/c++/11/bits/locale_classes.h:40, from /usr/include/c++/11/bits/ios_base.h:41, from /usr/include/c++/11/ios:42, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/bits/basic_string.h:6262:5: note: candidate: ‘template<class _CharT, class _Traits, class _Alloc> decltype (__char_traits_cmp_cat<_Traits>(0)) std::operator<=>(const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&)’ (rewritten) 6262 | operator<=>(const basic_string<_CharT, _Traits, _Alloc>& __lhs, | ^~~~~~~~ /usr/include/c++/11/bits/basic_string.h:6262:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/bits/ios_base.h:46, from /usr/include/c++/11/ios:42, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/system_error:261:3: note: candidate: ‘std::strong_ordering std::operator<=>(const std::error_code&, const std::error_code&)’ (rewritten) 261 | operator<=>(const error_code& __lhs, const error_code& __rhs) noexcept | ^~~~~~~~ /usr/include/c++/11/system_error:261:33: note: no known conversion for argument 1 from ‘Time’ to ‘const std::error_code&’ 261 | operator<=>(const error_code& __lhs, const error_code& __rhs) noexcept | ~~~~~~~~~~~~~~~~~~^~~~~ /usr/include/c++/11/system_error:387:3: note: candidate: ‘std::strong_ordering std::operator<=>(const std::error_condition&, const std::error_condition&)’ (rewritten) 387 | operator<=>(const error_condition& __lhs, | ^~~~~~~~ /usr/include/c++/11/system_error:387:38: note: no known conversion for argument 1 from ‘Time’ to ‘const std::error_condition&’ 387 | operator<=>(const error_condition& __lhs, | ~~~~~~~~~~~~~~~~~~~~~~~^~~~~ In file included from /usr/include/c++/11/bits/stl_algobase.h:67, from /usr/include/c++/11/bits/char_traits.h:39, from /usr/include/c++/11/ios:40, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/bits/stl_iterator.h:516:5: note: candidate: ‘template<class _IteratorL, class _IteratorR> constexpr bool std::operator>(const std::reverse_iterator<_IteratorL>&, const std::reverse_iterator<_IteratorR>&) requires requires{{std::operator>::__x->base() < std::operator>::__y->base()} -> decltype(auto) [requires std::convertible_to<<placeholder>, bool>];}’ 516 | operator>(const reverse_iterator<_IteratorL>& __x, | ^~~~~~~~ /usr/include/c++/11/bits/stl_iterator.h:516:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘const std::reverse_iterator<_IteratorL>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ In file included from /usr/include/c++/11/bits/stl_algobase.h:67, from /usr/include/c++/11/bits/char_traits.h:39, from /usr/include/c++/11/ios:40, from /usr/include/c++/11/ostream:38, from /usr/include/c++/11/iostream:39, from a.cpp:1: /usr/include/c++/11/bits/stl_iterator.h:1627:5: note: candidate: ‘template<class _IteratorL, class _IteratorR> constexpr bool std::operator>(const std::move_iterator<_IteratorL>&, const std::move_iterator<_IteratorR>&) requires requires{{std::operator>::__y->base() < std::operator>::__x->base()} -> decltype(auto) [requires std::convertible_to<<placeholder>, bool>];}’ 1627 | operator>(const move_iterator<_IteratorL>& __x, | ^~~~~~~~ /usr/include/c++/11/bits/stl_iterator.h:1627:5: note: template argument deduction/substitution failed: a.cpp:100:18: note: ‘Time’ is not derived from ‘const std::move_iterator<_IteratorL>’ 100 | if (x[i] > maxValue) { | ~~~~~^~~~~~~~~~ 根据报错修改代码
最新发布
05-12
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值