标签: constexpr

C++:为什么这个constexpr不是编译时常量

在下面的C++ 11代码中,对arraySize的最后一次调用会导致编译错误.显然这是因为y是运行时大小的数组,并且不能推导出y的arraySize模板参数N. 我不明白为什么x是一个编译时大小的数组,但y结束了运行时大小.arraySize模板函数直接取自Scott Meyers的"Effective Modern C++"第1项.

#include <cstddef>

template<typename T, std::size_t N>
constexpr std::size_t arraySize(T(&)[N]) noexcept { return N; }

struct S
{
    char c[10];
};

int main()
{
    S s;
    S* ps = &s;

    char x[arraySize(s.c)];
    char y[arraySize(ps->c)]; // why is y a runtime sized array?

    arraySize(x);
    arraySize(y); // error !?

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

templates constexpr c++11

10
推荐指数
1
解决办法
1215
查看次数

constexpr结束istream(sentinel)迭代器有什么意义?

N2976建议添加constexpr标准库中的某些位置.它指出iostreams不适用于constexprEXCEPT结束迭代器.所以istream_iterator,istreambuf_iterator并给予constexpr默认构造函数,就是这样.例如,您可以在libstdc ++实现中看到constexpr只在整个文件中出现一次.引发这一变化的LWG是#1129.它说:

istream_iteratoristreambuf_iterator应支持文字哨兵价值观.默认构造函数经常用于终止范围istreambuf_iterator,并且istream_iterator在迭代值类型时很容易成为文字值 .[其余省略]

这对我来说并没有多大意义.有人能告诉我他们的意思吗?

N3308是另一篇提到但没有解释问题的论文:

某些istream_iterator<T>构造函数必须是 constexprif T是文字类型.目的是允许存储一种T内联类型的现有实现技术继续工作.[libstdc ++这样做,_Tp _M_value]但是,它实际上排除了这种技术:T不需要标记默认和复制构造函数constexpr,如果不是,则 istream_iterator<T>构造函数不能被实例化 constexpr.

上面解释了普通的复制构造函数和析构函数,但不是默认构造函数标记为constexpr的原因.

此外,在在线GCC 5.2.0上进行测试,我复制了libstdc ++的实现.唯一的变化是我删除了constexpr istream_iterator().在这两种情况下,组件都是相同的.

随着constexpr

没有constexpr

c++ istream-iterator constexpr c++11

10
推荐指数
1
解决办法
357
查看次数

为什么我更喜欢类中的静态constexpr int而不是枚举类级别的积分常量?

C++ 17更新: static constexpr变量是隐式的,inline因此不需要外部定义.


原始问题:

假设我有一个常量列表,例如

struct Cls {
    static constexpr int N = 32;
    static constexpr int M = 64;
};
Run Code Online (Sandbox Code Playgroud)

这当然表明我为这些添加定义以避免可能发生的ODR使用问题,因此我需要:

constexpr int Cls::N;
constexpr int Cls::M;
Run Code Online (Sandbox Code Playgroud)

为什么我喜欢这个了

struct Cls {
    enum : int {
        N = 32,
        M = 64
    };
};
Run Code Online (Sandbox Code Playgroud)

从而节省了我的ODR使用难题N,M并且更真实地只是常量而不是它们自己的对象(如果这只是标题,那就更大了)并且更短.enum : long long如果需要,我可以明确指定类型或其他任何东西.第一个有什么优势?

c++ enums constexpr c++11

10
推荐指数
1
解决办法
1452
查看次数

为什么constexpr不是所有功能的默认值?

在放宽constexpr的规则之后,似乎这些功能可以在任何地方使用.它们也可以在常量(constexpr)和局部(可变)变量上调用.所以对我来说,它似乎只是编译器的一个提示(如内联).我只是继续在任何地方写它并在编译器抱怨时删除它.因此,如果可以在编译时评估函数,编译器似乎知道所有内容.为什么它不是默认行为,为什么我必须将任何东西标记为constexpr?

c++ constexpr c++14

10
推荐指数
1
解决办法
1036
查看次数

Constexpr lambda默认情况下?

根据n4487和其他c ++ 17引用,将会有新的lambda函数说明符 - constexpr如果存在,则"明确指定函数调用运算符是一个constexpr函数." .我理解lambda中常量表达式的动机.对我来说有趣的是提案的第4点,其中指出:

4)如果constexpr在lambda声明符中省略了说明符,则函数调用运算符(或模板)constexpr是否满足constexpr函数的要求.

这引出了两个问题:

  1. 为什么我们需要constexpr说明符?看起来lambda调用操作符是否将constexpr取决于它"满足constexpr函数的要求"的事实,而不是来自 constexpr说明符的存在.
  2. 如果constexpr默认情况下可以接受lambda,那么为什么不建议其他类型的函数 - 例如全局函数?如果编译器开始处理涵盖需求的所有函数,会产生什么影响constexpr

c++ lambda constexpr c++17

10
推荐指数
1
解决办法
638
查看次数

我应该更喜欢函数中的常量:constexpr const还是enum?

我习惯用定义我的常量enum { my_const = 123; },因为在类中,使用static constexpr需要在类定义之外的一些代码(参见这个问题).但是 - 功能体呢?最近我注意到人们只是constexpr在他们的功能中有变量(const实际上甚至没有打扰他们),我想知道我是不是一个傻瓜谁是我的时代背后

int foo(int x)
{
    enum : int { bar = 456 };
    return x + bar;
}
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是:在函数体中使用枚举而不是constexpr变量有什么好处吗?

c++ enums constexpr c++11

10
推荐指数
1
解决办法
611
查看次数

是否在constexpr静态成员的声明中需要constexpr说明符在类外部初始化?

C++17§10.1.5/ 1指出:

constexpr说明符将只应用于一个变量或变量模板的定义或功能或功能模板的声明.使用说明constexpr符声明的函数或静态数据成员 隐式地是内联函数或变量(10.1.6).如果函数或函数模板的任何声明都有一个 constexpr说明符,那么它的所有声明都应该包含说明 constexpr符.

因为类似的段落已在标准中存在C++ 11(§7.1.5/ 1),这是在引述由理查德·史密斯评论,其中他争辩说,C++标准并没有要求constexpr说明符之间匹配声明和变量的定义.在上段的最后一句明确要求constexpr符横跨匹配功能和函数模板的声明,但并没有提及变量声明.

§10.1.5/ 9指出:

constexpr对象声明中使用的说明符将对象声明为const.这样的对象应具有文字类型并应初始化.在任何constexpr变量声明中,初始化的完整表达式应为常量表达式(8.20).

当然,如果我们有一个单独的声明和定义,它们都需要匹配const,无论constexpr指定符是否需要匹配.

§12.2.3.2/ 2-3说:

2在其类定义中声明非内联静态数据成员不是定义,并且可能是除cv 之外的不完整类型void.未在类定义中内联定义的静态数据成员的定义应出现在包含成员类定义的命名空间范围内.在命名空间作用域的定义中,静态数据成员的名称应使用::运算符通过其类名限定.静态数据成员定义中的初始化表达式在其类的范围内(6.3.7).

3如果非易失性非内联const静态数据成员具有整数或枚举类型...如果使用说明constexpr符声明成员,则可以在没有初始化程序的命名空间范围内重新声明该成员 (此用法已弃用;请参阅D.1 ).其他静态数据成员的声明不应指定大括号或等于初始化器.

§D.1/ 1内容如下:

为了与先前的C++国际标准兼容,constexpr 可以在类外部冗余地重新声明静态数据成员而不使用初始化程序.不推荐使用此用法.

从中我们可以收集到,如果使用说明符声明成员constexpr,则命名空间范围定义是多余的, …

c++ language-lawyer constexpr c++11 c++17

10
推荐指数
1
解决办法
268
查看次数

枚举像计算常数

实际上这个"问题"感觉非常简单.在做一些计算出的图标偏移时,我想出了以下方法:

namespace Icons {

  struct IconSet {
    constexpr IconSet(size_t base_offset) noexcept
      : base_offset_(base_offset), icon(base_offset * 3), iconSmall(icon + 1), iconBig(icon + 2) {
    }
    size_t icon;
    size_t iconSmall;
    size_t iconBig;

    size_t base_offset_;

    constexpr size_t next() const {
      return base_offset_ + 1;
    }
  };


  static constexpr IconSet flower = IconSet(0);
  static constexpr IconSet tree = IconSet(flower.next());
  static constexpr IconSet forest = IconSet(tree.next());
  static constexpr IconSet mountain = IconSet(forest.next());

 }
Run Code Online (Sandbox Code Playgroud)

现在可以编写一个Icons::tree.iconBig例子来获取该图标的计算偏移量.基本上,设计师可以更改图标 - 有时也可以添加/删除 - 但总是按惯例提供整个设置(正常,小和大).

如你所见,这种方法的问题是我必须做这个next()功能并重复使用它 - 正常的枚举不会有这个缺点. …

c++ constexpr c++17

10
推荐指数
1
解决办法
678
查看次数

为什么允许一些非常量表达式作为constexpr逗号运算符的操作数?

考虑一个简单的例子:

int foo() {
    return 3;
}

template <int>
struct Bar {};

int a;

int main() {
    int b;
    //Bar<((void)foo(), 1)> bar1;  //case 1. compilation error as expected
    Bar<((void)a, 2)> bar2;        //case 2. no error (long shot but `a' has a linkage so maybe expected)
    Bar<((void)b, 3)> bar3;        //case 3. no error ? (`b' does not have linkage) 
    (void)bar2;
    (void)bar3;
}
Run Code Online (Sandbox Code Playgroud)

我会说这是一个错误,但最新的[clang][gcc]接受代码所以也许我错过了一些使代码有效的相关标准规则?

c++ comma-operator language-lawyer constexpr c++11

10
推荐指数
1
解决办法
263
查看次数

constexpr映射要使用什么类型?

理想情况下,我想写:

constexpr std:map<std::string, std::string> my_map = 
  {{"key1", "val1"}, {"key2", "val2"}, };
Run Code Online (Sandbox Code Playgroud)

要么

constexpr std:unordered_map<std::string, std::string> my_map =
  {{"key1", "val1"}, {"key2", "val2"}, };
Run Code Online (Sandbox Code Playgroud)

但是都不可能(至少在当前语言是不可能的)

那还有什么选择呢?

例如,我可以做以下事情:

constexpr std::initializer_list< std::pair<const char*, const char *> > my_map = 
  {{"key1", "val1"}, {"key2", "val2"}, };
Run Code Online (Sandbox Code Playgroud)

然后在运行std::map时需要构造一个。我知道我也可以使用inline代替constexpr,但是那时我将无法在编译时使用(也许在开发的后期)。但是,这有点不令人满意(因为我不得不在运行时仅出于查找目的构造映射),我想知道:是否有更好的解决方案?

c++ stdmap constexpr c++17

10
推荐指数
0
解决办法
180
查看次数