constexpr guard clause不会编译。

huangapple go评论65阅读模式
英文:

constexpr guard clause does not compile

问题

I wanted to add a constexpr guard clause in my code in order to avoid unnecessary indentation, but ran into this issue.

This compiles:

#include
#include

template
void inc(T& t) {
if constexpr (!std::is_arithmetic_v) {
return;
} else {
++t;
}
}

int main() {
int i = 1;
std::string s = "bar";
inc(i);
inc(s);
std::cout << "Success!";
}

Whereas this does not:

#include
#include

template
void inc(T& t) {
if constexpr (!std::is_arithmetic_v) {
return;
}
++t;
}

int main() {
int i = 1;
std::string s = "bar";
inc(i);
inc(s);
std::cout << "Success!";
}

Compiler error:

main.cpp:9:5: error: cannot increment value of type 'std::string'
++t;
^ ~
main.cpp:17:5: note: in instantiation of function template specialization 'incstd::string' requested here
inc(s);
^
1 error generated.

Why won't this work?

To clarify: I'm writing a googletest TYPED_TEST to test my code for various types, but some tests require the type to be incrementable. I thought to add a constexpr guard clause to skip types that do not support that operation.

英文:

I wanted to add a constexpr guard clause in my code in order to avoid unnecessary indentation, but ran into this issue.

This compiles:

#include &lt;string&gt;
#include &lt;iostream&gt;

template&lt;class T&gt;
void inc(T&amp; t) {
    if constexpr (!std::is_arithmetic_v&lt;T&gt;) {
        return;
    } else {
        ++t;
    }
}

int main() {
    int i = 1;
    std::string s = &quot;bar&quot;;
    inc(i);
    inc(s);
    std::cout &lt;&lt; &quot;Success!&quot;;
}

Whereas this does not:

#include &lt;string&gt;
#include &lt;iostream&gt;

template&lt;class T&gt;
void inc(T&amp; t) {
    if constexpr (!std::is_arithmetic_v&lt;T&gt;) {
        return;
    }
    ++t;
}

int main() {
    int i = 1;
    std::string s = &quot;bar&quot;;
    inc(i);
    inc(s);
    std::cout &lt;&lt; &quot;Success!&quot;;
}

Compiler error:

main.cpp:9:5: error: cannot increment value of type &#39;std::string&#39;
    ++t;
    ^ ~
main.cpp:17:5: note: in instantiation of function template specialization &#39;inc&lt;std::string&gt;&#39; requested here
    inc(s);
    ^
1 error generated.

Why won't this work?

To clarify: I'm writing a googletest TYPED_TEST to test my code for various types, but some tests requires the type to be incrementable. I thought to add a constexpr guard clause to skip types that does not support that operation.

答案1

得分: 3

An if constexpr branch that is taken and unconditionally exits the function doesn't prevent a check of the validity of substituted expressions following the if constexpr statement, for the same reason that a simple unconditional return statement doesn't prevent the same check.

当执行被采纳并无条件退出函数的 if constexpr 分支时,并不会阻止对在 if constexpr 语句之后被替代表达式的有效性进行检查,原因与简单的无条件 return 语句不会阻止相同的检查一样。

Of course, theoretically, if there is a statement that unconditionally exits from a function one could argue that it doesn't matter what comes after that statement and that it doesn't matter either whether substitution of template arguments results in a valid expression.

当然,从理论上讲,如果存在一个无条件退出函数的语句,可以争论说在该语句之后发生什么并不重要,而且是否替换模板参数导致有效表达式也无关紧要。

However, there is no such rule. A statement following an unconditional exit is still checked for validity after substitution in the same way any other non-discarded statement is checked.

然而,并没有这样的规则。在无条件退出之后的语句仍然会在替换后被检查其有效性,方式与任何其他未被丢弃的语句一样。

If there was such a rule, it would need to define exactly when validity of statements isn't checked. In general it is undecidable (in the sense of computability theory) whether a statement in a function is reachable. So at best you'd need to specify special cases such as a separate return statement in the same scope or a nested if constexpr branch as a condition for the special rule to apply.

如果存在这样的规则,它必须明确定义语句的有效性何时不会被检查。通常情况下,无法确定(从计算理论的角度看)函数中的语句是否可达。因此,最好的情况是需要指定特殊情况,例如在相同范围内的单独 return 语句或嵌套的 if constexpr 分支作为特殊规则应用的条件。

But then you'd have a weird difference depending on the exact form in which the function is written. I don't think adding this complexity would be beneficial overall. Also, there are other effects of just having the substituted statements, even if they are unreachable, e.g. regarding odr-use and implicit instantiation of template specializations, which would then also have different behavior depending on the exact syntactical form of the function body.

但是,这将会根据函数编写的确切形式产生奇怪的差异。我认为增加这种复杂性整体上并不会有益处。此外,即使这些替代语句是不可达的,仍然会产生其他影响,例如关于 odr-use 和模板特化的隐式实例化,这将取决于函数体的确切语法形式而产生不同的行为。

There is also no need for such a rule, because it can in practice always be achieved explicitly with a if constexpr. In your case the condition can be negated and then ++t can be placed into the true-branch to simplify the syntax a bit. Otherwise, the else branch can be taken. That this requires some extra punctuation and indentation is unlikely to be good enough reason to add complexity to the language. C++ isn't known to be very concise in syntax anyway.

也没有必要添加这样的规则,因为在实际中,可以始终使用 if constexpr 显式实现。在您的情况下,可以对条件取反,然后将 ++t 放入 true 分支以稍微简化语法。否则,可以选择 else 分支。这需要一些额外的标点符号和缩进,这不太可能是增加语言复杂性的足够好的理由。毕竟,C++ 在语法上不太简洁。

英文:

An if constexpr branch that is taken and unconditionally exits the function doesn't prevent a check of the validity of substituted expressions following the if constexpr statement, for the same reason that a simple unconditional return statement doesn't prevent the same check.

Of course, theoretically, if there is a statement that unconditionally exits from a function one could argue that it doesn't matter what comes after that statement and that it doesn't matter either whether substitution of template arguments results in a valid expression.

However, there is no such rule. A statement following an unconditional exit is still checked for validity after substitution in the same way any other non-discarded statement is checked.

If there was such a rule, it would need to define exactly when validity of statements isn't checked. In general it is undecidable (in the sense of computability theory) whether a statement in a function is reachable. So at best you'd need to specify special cases such as a separate return statement in the same scope or a nested if constexpr branch as condition for the special rule to apply.

But then you'd have a weird difference depending on the exact form in which the function is written. I don't think adding this complexity would be beneficial overall. Also, there are other effects of just having the substituted statements, even if they are unreachable, e.g. regarding odr-use and implicit instantiation of template specializations, which would then also have different behaviour depending on the exact syntactical form of the function body.

There is also no need for such a rule, because it can in practice always be achieved explicitly with a if constexpr. In your case the condition can be negated and then ++t can be placed into the true-branch to simplify the syntax a bit. Otherwise, the else branch can be taken. That this requires some extra punctuation and indentation is unlikely to be good enough reason to add complexity to the language. C++ isn't known to be very concise in syntax anyway.

huangapple
  • 本文由 发表于 2023年6月30日 04:04:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/76584292.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定