标签: constexpr

由于定义顺序,"令人惊讶"的常量初始化

在阅读关于constexpr幻灯片时,介绍是关于"令人惊讶的动态初始化与consts".这个例子是

struct S {
    static const int c;
};
const int d = 10 * S::c;
const int S::c = 5;
Run Code Online (Sandbox Code Playgroud)

唉,音轨缺失了,音符也是如此,所以我只能猜到这里的含义.

是否正确d地"动态地"初始化,因为之前S::c定义了吗? d声明S::c是之前d可能是不够的,编译器需要完整的定义,对不对?

那就是说,我怀疑,在下面的例子中d 静态初始化?

struct S {
    static const int c;
};
const int S::c = 5;
const int d = 10 * S::c;  // now _after_ defn of S::c
Run Code Online (Sandbox Code Playgroud)

并采取蛋糕,在C++ 11,什么必须是constexpr完全静态初始化?S::c …

c++ initialization const constexpr c++11

13
推荐指数
1
解决办法
984
查看次数

在编译时测试endianess:这个constexpr函数是否符合标准?

在编译时搜索了一种检查endianess的方法后,我提出了以下解决方案:

static const int a{1};

constexpr bool is_big_endian()
{
    return *((char*)&(a)) == 1;
}
Run Code Online (Sandbox Code Playgroud)

GCC仅在需要constexpr的某些上下文中接受此代码:

int b[is_big_endian() ? 12 : 25]; //works
std::array<int, testendian() ? 12 : 25> c;  //fails
Run Code Online (Sandbox Code Playgroud)

对于第二种情况,GCC说error: accessing value of ‘a’ through a ‘char’ glvalue in a constant expression.我无法在禁止此类事件的标准中找到任何内容.也许有人可以澄清GCC在哪种情况下是正确的?

c++ constexpr c++11

13
推荐指数
1
解决办法
1489
查看次数

constexpr,static_assert和inlining

我之前根据参数是否constexpr询问函数重载.我正试图解决这个问题的令人失望的答案,以建立一个更聪明的断言功能.这大致是我想做的事情:

inline void smart_assert (bool condition) {
    if (is_constexpr (condition))
        static_assert (condition, "Error!!!");
    else
        assert (condition);
}
Run Code Online (Sandbox Code Playgroud)

基本上,我们的想法是编译时检查总是比运行时检查更好,如果可以在编译时检查.但是,由于内联和常量折叠之类的东西,我不能总是知道是否可以进行编译时间检查.这意味着可能存在assert (condition)编译的情况,assert(false)代码只是等待我运行它并在我发现错误之前执行该路径.

因此,如果有某种方法来检查条件是否是constexpr(由于内联或其他优化),我可以static_assert在可能的情况下调用,否则返回运行时断言.幸运的是,gcc具有内在函数__builtin_constant_p (exp),如果exp是constexpr 则返回true .我不知道其他编译器是否有这种内在的,但我希望这可以解决我的问题.这是我提出的代码:

#include <cassert>
#undef IS_CONSTEXPR

#if defined __GNUC__
    #define IS_CONSTEXPR(exp) __builtin_constant_p (exp)
#else
    #define IS_CONSTEXPR(exp) false
#endif
// TODO: Add other compilers

inline void smart_assert (bool const condition) { 
    static_assert (!IS_CONSTEXPR(condition) or condition, "Error!!!");
    if (!IS_CONSTEXPR(condition))
        assert (condition);
}

#undef IS_CONSTEXPR
Run Code Online (Sandbox Code Playgroud)

static_assert …

c++ inline static-assert constexpr c++11

13
推荐指数
2
解决办法
4713
查看次数

允许在constexpr函数中进行函数指针比较吗?

假设我有一个constexpr函数指针数组,我想编写一个constexpr函数来查找指定函数的数组索引.

我可能有这样的代码:

void test1(){}void test2(){}void test3(){}void test4(){}

typedef void(*func)(void);
constexpr func funcs[] = { &test1, &test2, &test3 };

constexpr int FindMatchingIdx (const func work, const int idx) {
    return (work == funcs[idx]) ? (idx) : (FindMatchingIdx(work, idx + 1));
}

constexpr unsigned int loc = FindMatchingIdx (&test1,0);
Run Code Online (Sandbox Code Playgroud)

现在这个代码在Clang和MSVC上编译,但是GCC只会FindMatchingIdx在使用数组中的第一个元素调用时进行编译.如果FindMatchingIdx调用test1,GCC将编译代码,但如果FindMatchingIdx调用,test2test3GCC将无法编译代码,给出错误消息:

错误:'(test1!= test2)'不是常量表达式.

如果FindMatchingIdx必须递归,GCC将无法将其视为constexpr功能.这是GCC中的错误吗?函数指针比较如何在constexpr函数内部工作?显然,它不能使用由链接器分配的实际指针值.

工作示例:https://godbolt.org/g/xfv1PM

c++ language-lawyer constexpr c++11 c++14

13
推荐指数
1
解决办法
447
查看次数

在VS2017中不是编译时常量表达式

VS2017 15.1无法编译以下代码:

template<int data_size>
struct Data { };

template<int s>
struct Base
{
    static constexpr int size() { return s; }
};

template<int s>
struct Derived : Base<s>   // struct Derived
{
    Data<Base<s>::size()> data;
};

int main()
{
    Derived<1> c;
}
Run Code Online (Sandbox Code Playgroud)

错误是:

error C2975: 'data_size': invalid template argument for 'Data', expected compile-time constant expression
note: see declaration of 'data_size'
note: see reference to class template instantiation 'Derived<s>' being compiled
Run Code Online (Sandbox Code Playgroud)

如果我不是从中衍生Derived出来的Base,那么错误就会消失.使用gcc 5.4.0和clang 4.0.0在这两种情况下一切都很好.

这段代码有什么问题吗?

c++ templates constexpr c++11 visual-studio-2017

13
推荐指数
1
解决办法
728
查看次数

是什么原因`std :: exchange`不是`constexpr`?

std::exchange,在C++ 14中引入,规定如下:

template< class T, class U = T >
T exchange( T& obj, U&& new_value );
Run Code Online (Sandbox Code Playgroud)

替换objwith 的值new_value并返回旧值obj.

以下是cppreference的可能实现:

template<class T, class U = T>
T exchange(T& obj, U&& new_value)
{
    T old_value = std::move(obj);
    obj = std::forward<U>(new_value);
    return old_value;
}
Run Code Online (Sandbox Code Playgroud)

据我所知,没有什么可以防止std::exchange被标记为constexpr.有没有理由我错过了为什么不能constexpr,或者这只是一个疏忽?

c++ std constexpr c++14

13
推荐指数
1
解决办法
834
查看次数

杀死魔术数字:“ const int” vs“ constexpr int”(或最后没有区别)

假设我有一个magic number想要摆脱的...

//whatever.cpp

for (int i = 0; i < 42; i++)
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

我可以通过两种方式杀死它:

在源文件中带有const int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42
或带有。constexpr int SOMETHING_SOMETHING_MEANING_OF_LIFE = 42
.cpp

在这种情况下,两者之间是否有任何有意义的区别(我记得编译器推断出-在任何一种情况下-值均未更改,因此42实际上将其硬编码在结果循环/展开循环/任何机器代码中)或归结为个人品味吗?

在一个相关的问题中:如果magic number在标头(.h)文件而不是源(.ccp)文件中声明了(从而替换它的事物),那会发生什么变化(如果是,则如何改变)呢?

c++ const magic-numbers constexpr

13
推荐指数
2
解决办法
943
查看次数

在 constexpr 构造函数中初始化数组是否合法?

下面的代码合法吗?

template <int N>
class foo {
public:
    constexpr foo()
    {
        for (int i = 0; i < N; ++i) {
            v_[i] = i;
        }
    }

private:
    int v_[N];
};

constexpr foo<5> bar;
Run Code Online (Sandbox Code Playgroud)

Clang 接受它,但 GCC 和 MSVC 拒绝它。

GCC 的错误是:

main.cpp:15:18: error: 'constexpr foo<N>::foo() [with int N = 5]' called in a constant expression
   15 | constexpr foo<5> bar;
      |                  ^~~
main.cpp:4:15: note: 'constexpr foo<N>::foo() [with int N = 5]' is not usable as a 'constexpr' function because:
    4 …
Run Code Online (Sandbox Code Playgroud)

c++ compile-time-constant template-meta-programming constexpr

13
推荐指数
1
解决办法
839
查看次数

如何如此快速地评估 const expr

我一直在尝试在编译时计算的 const 表达式。但是我玩了一个在编译时执行时看起来非常快的示例。

#include<iostream> 

constexpr long int fib(int n) { 
    return (n <= 1)? n : fib(n-1) + fib(n-2); 
} 

int main () {  
    long int res = fib(45); 
    std::cout << res; 
    return 0; 
} 
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时,大约需要 7 秒才能运行。到现在为止还挺好。但是,当我更改long int res = fib(45)const long int res = fib(45)它需要没有哪怕一秒钟。据我了解,它是在编译时评估的。 但是编译大约需要0.3秒

编译器怎么能这么快地评估它,但在运行时却需要更多的时间?我正在使用 gcc 5.4.0。

c++ constants constexpr

13
推荐指数
1
解决办法
377
查看次数

使用 constexpr 返回指针

从 C++20 开始,我们可以在编译时分配内存,我们必须在编译时释放它。因此,这给我提出了一些问题:首先,为什么这行得通?

constexpr int* return_ptr() {
    return new int{ 1 };
}

void call_return_ptr(){
    int* int_ptr = return_ptr();
}

int main() {
    call_return_ptr();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我正在使用从编译时返回的 ptrconstexpr并且没有释放它。根据我的理解,这应该是一个错误。其次,如果第一个示例有效,那么为什么这不起作用:

constexpr int* return_ptr() {
    return new int{ 1 };
}

void call_return_ptr(){
    constexpr int* int_ptr = return_ptr();
}

int main() {
    call_return_ptr();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

即使我们在编译时尝试删除指针,如下所示:

constexpr int* return_ptr() {
    return new int{ 1 };
}

constexpr void call_return_ptr(){
    constexpr int* int_ptr = return_ptr();
    delete int_ptr;
} …
Run Code Online (Sandbox Code Playgroud)

c++ constexpr c++20

13
推荐指数
1
解决办法
546
查看次数