有关constexpr构造函数的问题

搬砖小龙虾 2018-10-30 08:41:03
在翻阅c++ primer时了解到,构造函数是没有返回类型的,但是constexpr函数需要返回类型,所以为什么构造函数能声明为constexpr?
...全文
502 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
搬砖小龙虾 2018-11-02
  • 打赏
  • 举报
回复
引用 5 楼 xskxzr 的回复:
构造函数是特殊的成员函数,constexpr构造函数有其他特殊的规则。
嗯嗯,有点明白了
xskxzr 2018-11-02
  • 打赏
  • 举报
回复
构造函数是特殊的成员函数,constexpr构造函数有其他特殊的规则。
真相重于对错 2018-10-31
  • 打赏
  • 举报
回复

cppreference.com
创建账户

页面
讨论

变换

查看
编辑
历史

Adobe Creative Cloud for Teams starting at $29.99 per month.
ads via Carbon
constexpr 指定符(C++11 起)

C++

C++ 语言

声明


constexpr - 指定变量或函数的值能出现在常量表达式中

解释

constexpr 指定符声明可以在编译时求得函数或变量的值。然后这些变量和函数(若给定了合适的函数参数)可用于仅允许编译时常量表达式之处。用于对象或非静态成员函数 (C++14 前)声明的 constexpr 指定符隐含 const 。用于函数声明的 constexpr 指定符或 static 成员变量 (C++17 起)隐含 inline 。

constexpr 变量必须满足下列要求:

其类型必须是字面类型 (LiteralType) 。
它必须被立即初始化
其初始化的完整表达式,包括所有隐式转换、构造函数调用等,都必须是常量表达式

constexpr 函数必须满足下列要求:

它必须非虚

(C++20 前)

其返回类型必须是字面类型 (LiteralType)
其每个参数都必须是字面类型 (LiteralType)
至少存在一组参数值,使得函数的一个调用能为被求值的核心常量表达式的子表达式(对于构造函数为足以用于常量初始化器) (C++14 起)。不要求对这点的诊断。

函数体必须是被删除或被默认化,或只含有下列内容:

空语句(平凡分号)
static_assert 声明
不定义类或枚举的 typedef 声明及别名声明
using 声明
using 指令
恰好一条 return 语句。

(C++14 前)

函数体必须是被删除或被默认化,或含有下列内容外的任何语句:

asm 声明
goto 语句
拥有异于 case 和 default 标号的语句
try 块
非字面类型的变量定义
静态或线程存储期变量的定义
不进行初始化的变量定义。

(C++14 起)

constexpr 构造函数必须满足下列要求:

其每个参数都必须是字面类型 (LiteralType) 。
该类不能有虚基类
该构造函数不可有函数 try 块

构造函数体必须被删除或被默认化或只含有下列内容:

空语句
static_assert 声明
不定义类或枚举的 typedef 声明及别名声明
using 声明
using 指令

(C++14 前)

构造函数体的复合语句必须满足 constexpr 函数体的限制

(C++14 起)

对于 class 或 struct 的构造函数,每个子对象和每个非变体非 static 数据成员必须被初始化。若类是类联合体类,对于其每个非空匿名联合体成员,必须恰好有一个变体成员被初始化
对于非空 union 的构造函数,恰好有一个非 static 数据成员被初始化
每个被选作初始化非 static 成员和基类的构造函数必须是 constexpr 构造函数。

对于 constexpr 函数模板和类模板的 constexpr 函数成员,必须至少有一个特化满足上述要求。其他特化仍被认为是 constexpr ,尽管常量表达式中不能出现这种函数的调用。
注意

因为 noexcept 运算符始终对常量表达式返回 true ,故它可用于检查具体特定的 constexpr 函数调用是否采用常量表达式分支:

constexpr int f();
constexpr bool b1 = noexcept(f()); // false, constexpr 函数未定义
constexpr int f() { return 0; }
constexpr bool b2 = noexcept(f()); // true, f() 是常量表达式

(C++17 前)

constexpr 构造函数允许用于非字面类型的类。例如, std::unique_ptr 的默认构造函数是 constexpr ,允许常量初始化。

引用变量可声明为 constexpr (其初始化器必须是引用常量表达式):

static constexpr int const& x = 42; // 到 const int 对象的 constexpr 引用
// (该对象拥有静态存储期,因为 static 引用续命)

关键词

constexpr
示例

计算阶乘的 C++11 constexpr 函数的定义,及扩展字符串字面量的字面类型:

运行此代码

#include <iostream>
#include <stdexcept>

// C++11 constexpr 函数使用递归而非迭代
// ( C++14 constexpr 函数可使用局部变量和循环)
constexpr int factorial(int n)
{
return n <= 1? 1 : (n * factorial(n - 1));
}

// 字面类
class conststr {
const char* p;
std::size_t sz;
public:
template<std::size_t N>
constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}

// constexpr 函数通过抛异常来提示错误
// C++11 中,它们必须用条件运算符?:这么做
constexpr char operator[](std::size_t n) const
{
return n < sz ? p[n] : throw std::out_of_range("");
}
constexpr std::size_t size() const { return sz; }
};

// C++11 constexpr 函数必须把一切放在单条 return 语句中
// ( C++14 无该要求)
constexpr std::size_t countlower(conststr s, std::size_t n = 0,
std::size_t c = 0)
{
return n == s.size() ? c :
'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) :
countlower(s, n + 1, c);
}

// 输出函数要求编译时常量,以测试
template<int n>
struct constN
{
constN() { std::cout << n << '\n'; }
};

int main()
{
std::cout << "4! = " ;
constN<factorial(4)> out1; // 在编译时计算

volatile int k = 8; // 不允许使用 volatile 者优化
std::cout << k << "! = " << factorial(k) << '\n'; // 运行时计算

std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
constN<countlower("Hello, world!")> out2; // 隐式转换到 conststr
}

输出:

4! = 24
8! = 40320
the number of lowercase letters in "Hello, world!" is 9

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
DR 应用于 出版时的行为 正确行为
CWG 1911 C++14 不允许对于非字面类型的 constexpr 构造函数 在常量初始化中允许
CWG 2004 C++14 在常量表达式中允许复制/移动有 mutable 成员的联合体 去除 mutable 变体隐式复制/移动的资格
CWG 2163 C++14 尽管 goto 在 constexpr 函数中被禁止,标号却得到允许 标号也被禁止
CWG 2268 C++14 cwg 2004 曾禁止了复制/移动有 mutable 成员的联合体 若该对象在常量表达式中创建,则允许
参阅

常量表达式

首页社区专页新闻动态最近更改随机页面帮助

链入页面相关更改上传文件特殊页面打印版本永久链接页面信息

其他语言

DeutschEnglishEspañolFrançaisItaliano日本語PortuguêsРусский

本页面最后修改于2018年6月18日 (星期一) 23:05。

隐私政策 关于cppreference.com 免责声明

Powered by MediaWiki Powered by GeSHi Hosted by Tiger Technologies

搬砖小龙虾 2018-10-31
  • 打赏
  • 举报
回复
引用 1 楼 幻夢之葉 的回复:
constexpr没有必须要返回值的规定吧?
constexpr函数是指能用于常量表达式的函数。函数的返回值类型以及所有的形参的类型必须是字面值(算数类型,引用,指针)类型,而且函数中必须只有一条return语句。
搬砖小龙虾 2018-10-31
  • 打赏
  • 举报
回复
引用 3 楼 真相重于对错 的回复:
cppreference.com
创建账户

页面
讨论

变换

查看
编辑
历史

Adobe Creative Cloud for Teams starting at $29.99 per month.
ads via Carbon
constexpr 指定符(C++11 起)

C++

C++ 语言

声明


constexpr - 指定变量或函数的值能出现在常量表达式中

解释

constexpr 指定符声明可以在编译时求得函数或变量的值。然后这些变量和函数(若给定了合适的函数参数)可用于仅允许编译时常量表达式之处。用于对象或非静态成员函数 (C++14 前)声明的 constexpr 指定符隐含 const 。用于函数声明的 constexpr 指定符或 static 成员变量 (C++17 起)隐含 inline 。

constexpr 变量必须满足下列要求:

其类型必须是字面类型 (LiteralType) 。
它必须被立即初始化
其初始化的完整表达式,包括所有隐式转换、构造函数调用等,都必须是常量表达式

constexpr 函数必须满足下列要求:

它必须非虚

(C++20 前)

其返回类型必须是字面类型 (LiteralType)
其每个参数都必须是字面类型 (LiteralType)
至少存在一组参数值,使得函数的一个调用能为被求值的核心常量表达式的子表达式(对于构造函数为足以用于常量初始化器) (C++14 起)。不要求对这点的诊断。

函数体必须是被删除或被默认化,或只含有下列内容:

空语句(平凡分号)
static_assert 声明
不定义类或枚举的 typedef 声明及别名声明
using 声明
using 指令
恰好一条 return 语句。

(C++14 前)

函数体必须是被删除或被默认化,或含有下列内容外的任何语句:

asm 声明
goto 语句
拥有异于 case 和 default 标号的语句
try 块
非字面类型的变量定义
静态或线程存储期变量的定义
不进行初始化的变量定义。

(C++14 起)

constexpr 构造函数必须满足下列要求:

其每个参数都必须是字面类型 (LiteralType) 。
该类不能有虚基类
该构造函数不可有函数 try 块

构造函数体必须被删除或被默认化或只含有下列内容:

空语句
static_assert 声明
不定义类或枚举的 typedef 声明及别名声明
using 声明
using 指令

(C++14 前)

构造函数体的复合语句必须满足 constexpr 函数体的限制

(C++14 起)

对于 class 或 struct 的构造函数,每个子对象和每个非变体非 static 数据成员必须被初始化。若类是类联合体类,对于其每个非空匿名联合体成员,必须恰好有一个变体成员被初始化
对于非空 union 的构造函数,恰好有一个非 static 数据成员被初始化
每个被选作初始化非 static 成员和基类的构造函数必须是 constexpr 构造函数。

对于 constexpr 函数模板和类模板的 constexpr 函数成员,必须至少有一个特化满足上述要求。其他特化仍被认为是 constexpr ,尽管常量表达式中不能出现这种函数的调用。
注意

因为 noexcept 运算符始终对常量表达式返回 true ,故它可用于检查具体特定的 constexpr 函数调用是否采用常量表达式分支:

constexpr int f();
constexpr bool b1 = noexcept(f()); // false, constexpr 函数未定义
constexpr int f() { return 0; }
constexpr bool b2 = noexcept(f()); // true, f() 是常量表达式

(C++17 前)

constexpr 构造函数允许用于非字面类型的类。例如, std::unique_ptr 的默认构造函数是 constexpr ,允许常量初始化。

引用变量可声明为 constexpr (其初始化器必须是引用常量表达式):

static constexpr int const& x = 42; // 到 const int 对象的 constexpr 引用
// (该对象拥有静态存储期,因为 static 引用续命)

关键词

constexpr
示例

计算阶乘的 C++11 constexpr 函数的定义,及扩展字符串字面量的字面类型:

运行此代码

#include <iostream>
#include <stdexcept>

// C++11 constexpr 函数使用递归而非迭代
// ( C++14 constexpr 函数可使用局部变量和循环)
constexpr int factorial(int n)
{
return n <= 1? 1 : (n * factorial(n - 1));
}

// 字面类
class conststr {
const char* p;
std::size_t sz;
public:
template<std::size_t N>
constexpr conststr(const char(&a)[N]): p(a), sz(N - 1) {}

// constexpr 函数通过抛异常来提示错误
// C++11 中,它们必须用条件运算符?:这么做
constexpr char operator[](std::size_t n) const
{
return n < sz ? p[n] : throw std::out_of_range("");
}
constexpr std::size_t size() const { return sz; }
};

// C++11 constexpr 函数必须把一切放在单条 return 语句中
// ( C++14 无该要求)
constexpr std::size_t countlower(conststr s, std::size_t n = 0,
std::size_t c = 0)
{
return n == s.size() ? c :
'a' <= s[n] && s[n] <= 'z' ? countlower(s, n + 1, c + 1) :
countlower(s, n + 1, c);
}

// 输出函数要求编译时常量,以测试
template<int n>
struct constN
{
constN() { std::cout << n << '\n'; }
};

int main()
{
std::cout << "4! = " ;
constN<factorial(4)> out1; // 在编译时计算

volatile int k = 8; // 不允许使用 volatile 者优化
std::cout << k << "! = " << factorial(k) << '\n'; // 运行时计算

std::cout << "the number of lowercase letters in \"Hello, world!\" is ";
constN<countlower("Hello, world!")> out2; // 隐式转换到 conststr
}

输出:

4! = 24
8! = 40320
the number of lowercase letters in "Hello, world!" is 9

缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。
DR 应用于 出版时的行为 正确行为
CWG 1911 C++14 不允许对于非字面类型的 constexpr 构造函数 在常量初始化中允许
CWG 2004 C++14 在常量表达式中允许复制/移动有 mutable 成员的联合体 去除 mutable 变体隐式复制/移动的资格
CWG 2163 C++14 尽管 goto 在 constexpr 函数中被禁止,标号却得到允许 标号也被禁止
CWG 2268 C++14 cwg 2004 曾禁止了复制/移动有 mutable 成员的联合体 若该对象在常量表达式中创建,则允许
参阅

常量表达式

首页社区专页新闻动态最近更改随机页面帮助

链入页面相关更改上传文件特殊页面打印版本永久链接页面信息

其他语言

DeutschEnglishEspañolFrançaisItaliano日本語PortuguêsРусский

本页面最后修改于2018年6月18日 (星期一) 23:05。

隐私政策 关于cppreference.com 免责声明

Powered by MediaWiki Powered by GeSHi Hosted by Tiger Technologies
请问能更清楚地指导一下嘛
幻夢之葉 2018-10-31
  • 打赏
  • 举报
回复
constexpr没有必须要返回值的规定吧?

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧