英文:
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 <string>
#include <iostream>
template<class T>
void inc(T& t) {
if constexpr (!std::is_arithmetic_v<T>) {
return;
} else {
++t;
}
}
int main() {
int i = 1;
std::string s = "bar";
inc(i);
inc(s);
std::cout << "Success!";
}
Whereas this does not:
#include <string>
#include <iostream>
template<class T>
void inc(T& t) {
if constexpr (!std::is_arithmetic_v<T>) {
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 'inc<std::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 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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论