C++ 如果有';这是一个constexpr if语句,为什么其他constexpr语句不能呢?

C++ 如果有';这是一个constexpr if语句,为什么其他constexpr语句不能呢?,c++,c++17,C++,C++17,如果C++17中只包含constexpr,有什么理由吗 我可以这样做: template <int N> constexpr int fib() { if constexpr (N == 1 || N == 2) { return 1; } else { return fib<N - 1>() + fib<N - 2>(); } } 使用开关constexpr 甚至在不使用模板替换/递归模板函数的情况下

如果C++17中只包含constexpr,有什么理由吗

我可以这样做:

template <int N>
constexpr int fib() {
    if constexpr (N == 1 || N == 2) {
        return 1;
    } else {
        return fib<N - 1>() + fib<N - 2>();
    }
}
使用
开关constexpr

甚至在不使用模板替换/递归模板函数的情况下,使用
for constexpr
/
而使用constexpr
展开过早的编译时循环:

constexpr void printFoo() {
    for constexpr (auto i = 0; i < 10; i++) {
        cout << fib<i>() << endl;
    }
}
constexpr void printFoo(){
对于constexpr(自动i=0;i<10;i++){

CC++标准委员会一般不会因为“看起来很酷”而添加新的特性。。每个新功能只有在提交了一篇论文后才会添加,该论文提出了精心编制的法律术语,精确地指定了功能的语法和语义。由于专家们对所有含义进行了详细分析,这些术语通常会经过多次修订

这为添加新特性提供了一个自然的障碍:如果它将添加到语言中的功能不足以使这种繁重的体验变得有价值,那么没有人会正式提出它

如果constexpr
是该语言的一个有价值的补充(请尝试重写代码,不要使用它,您会看到原因),并且指定它并没有那么复杂:如果条件为true,则丢弃第二个子语句,否则丢弃第一个子语句

相比之下,
switch-constexpr
在措辞上会造成更大的困难,因为
switch
语句更为复杂。(不过,欢迎您尝试一下。)例如,您自然会对其工作方式有一个期望:

switch constexpr (x) {
  case 1:
    bar<x>();
    if constexpr(y) { break; }
  case 2:
    baz<x>();
}
开关constexpr(x){
案例1:
bar();
如果constexpr(y){break;}
案例2:
baz();
}
也就是说,如果
x
为1且
y
为真,则不会实例化
baz
,但如果
x
为1且
y
为假,则会实例化
baz
。如果需要这些语义,则需要找出标准ESE,它必须指定一个有效的过程来准确地确定哪种类型要丢弃的h语句(请记住,这些
if
s和
switch
es可以任意嵌套)。如果您不想要这些语义,您的
switch constexpr
可能不会比一堆
If constexpr
更强大,但与正常的
switch
语句相比会有一些限制


这些困难随着constexpr的
而进一步增加。现在,这可能是值得的。但必须有人付出努力。

如果constexpr
是在接近C++17定稿时提出的

修饰(比如
开关
)可能推迟了它的加入

像“强制循环展开”这样的花哨游戏肯定会有

需要改变C++标准的实际工作。你必须在编译器中实现它,证明它是可以完成的,说服其他编译器编写者应该是容易的或值得的努力,去弄清楚它应该如何在标准中措辞清楚和明确,让委员会的其他成员相信你的改变不是简单的。关于语言等

<>不需要理由“强”>“不”/“强”发生。事情不会一直发生。C++改进不是一些自然过程,除非有人停止它,


Tl;dr:因为你没有提出,也没有通过标准化来实现。从今天开始,它可能是在C++20中提出的。“我不值得”提出并不是借口:这是需要做的工作,不是令人敬畏的恩赐。一个人通过做工作变得很棒。“我很懒”这是一个我非常熟悉的借口。

不是答案,但评论太长。您可以使用
#pragma unroll
在英特尔(R)编译器中展开编译时循环

void bar();

constexpr void foo() {
    #pragma unroll(10)
    for (auto i = 0; i < 10; i++) {
        bar();
    }
}

void baz()
{
    foo();
}
void bar();
constexpr void foo(){
#布拉格展开(10)
用于(自动i=0;i<10;i++){
bar();
}
}
void baz()
{
foo();
}

然后写一个建议。“看起来酷多了”这不是一个很好的理由。我相信我们只得到了
if constexpr
,因为如果我们试图同时包含整个批次的话,时间会更长;
if constexpr
的优点和缺点比
for constexpr
switch constexpr
更容易衡量。“switch constexpr看起来酷多了”。准备好成为一名巨魔吧。如果你愿意花宝贵的时间研究并写出一份好的提案,你就足够有声望了。我投票结束这个问题,因为“为什么X不是语言功能?”?"对于任何人来说,这都不是一个可以令人满意的问题。这不是一个必须在编译器中实现的正式要求。没有太多的正式要求,而且大部分都是程序性的。但这当然有助于说服WG21。在这种情况下,这是语法上的糖分。WG21主要关心的不是它是否可以被实现已修订,但语义是否定义良好且与语言的其他部分不冲突。@msalters是否constexor general loop展开真的只是糖?我的意思是,指定什么是可以的,什么是不可以的。索引变量的地址是否更改?或者看起来很疯狂。索引变量的地址到底是什么,insIDEA
constexpr
loop?禁止直接获取地址似乎是合乎逻辑的。这是完全可以解释/教导的:“编译器在编译时执行循环,因此没有运行时地址”@msalters所以我不能传递对该值的引用?即,没有ODR用法。或者应该实例化一个临时值吗?如果循环是
for(int x=0;test(x);inc(x))
?一篇初始论文可能会建立从
switch constepr
到一个等效但更详细的

void bar();

constexpr void foo() {
    #pragma unroll(10)
    for (auto i = 0; i < 10; i++) {
        bar();
    }
}

void baz()
{
    foo();
}