当我们想使用 static_assert
在 if constexpr
我们必须使条件依赖于某个模板参数。有趣的是,当代码包含在 lambda 中时,gcc 和 clang 不同意。
下面的代码用 gcc 编译,但 clang 触发断言,即使 if constexpr
不可能是真的。
#include <utility>
template<typename T> constexpr std::false_type False;
template<typename T>
void foo() {
auto f = [](auto x) {
constexpr int val = decltype(x)::value;
if constexpr(val < 0) {
static_assert(False<T>, "AAA");
}
};
f(std::integral_constant<int, 1>{});
}
int main() {
foo<int>();
}
Live example here .
它可以通过替换
False<T>
轻松修复来自 False<decltype(x)>
.所以问题是:哪个编译器是正确的?我认为 gcc 是正确的,因为
static_assert
中的条件依赖于 T
,但我不确定。
最佳答案
来自 [stmt.if]/2 (强调我的)
If the if statement is of the form if constexpr, the value of the condition shall be a contextually converted constant expression of type bool; this form is called a constexpr if statement. If the value of the converted condition is false, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement. During the instantiation of an enclosing templated entity ([temp.pre]), if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.
读到人们会认为静态断言会被删除,但事实并非如此。
静态断言在模板的第一阶段被触发,因为编译器知道它总是假的。
来自 [temp.res]/8 (强调我的)
The validity of a template may be checked prior to any instantiation. [ Note: Knowing which names are type names allows the syntax of every template to be checked in this way. — end note ] The program is ill-formed, no diagnostic required, if:
- (8.1) no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or
[...]
是的,您的
False<T>
取决于 T
.问题在于泛型 lambda 本身就是一个模板,而 False<T>
不依赖于 lambda 的任何模板参数。对于
T
那个False<T>
为假,静态断言将始终为假,无论将哪个模板参数发送到 lambda。编译器可以看到模板
operator()
的任何实例化。 ,静态断言将始终为当前 T 触发。因此编译器错误。对此的解决方案是依赖于
x
:template<typename T>
void foo() {
auto f = [](auto x) {
if constexpr(x < 0) {
static_assert(False<decltype(x)>, "AAA");
}
};
f(std::integral_constant<int, 1>{});
}
Live example
关于c++ - 如果 lambda 中带有 static_assert 的 constexpr,哪个编译器是正确的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59647445/