繁体   English   中英

如果 lambda 中带有 static_assert 的 constexpr,哪个编译器是正确的?

[英]if constexpr with static_assert in lambda, which compiler is correct?

当我们想在if constexpr使用static_assert ,我们必须使条件依赖于某个模板参数。 有趣的是,当代码包含在 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>();
}

现场示例在这里

通过将False<T>替换为False<decltype(x)>可以轻松修复它。

所以问题是:哪个编译器是正确的? 我认为 gcc 是正确的,因为static_assert的条件取决于T ,但我不确定。

这里通常的规则是[temp.res]/8

程序格式错误,无需诊断,如果: 不能为模板或 constexpr 的子语句生成有效的特化 模板中的 if 语句且模板未实例化

实例化foo<T> ,您拥有的static_assert不再依赖。 它变为static_assert(false) - 对于泛型 lambda f的调用运算符的所有可能实例化。 这是格式错误的,不需要诊断。 Clang 诊断,gcc 没有。 两者都是正确的。

请注意,这里的static_assert丢弃并不重要。

通过将False<T>替换为False<decltype(x)>可以轻松修复它。

这使static_assert依赖于泛型 lambda,现在我们进入一种状态,假设可能存在有效的特化,因此我们不再是格式错误的,ndr。

来自[stmt.if]/2 (强调我的)

如果 if 语句的形式为 if constexpr,则条件的值应为上下文转换的 bool 类型常量表达式; 这种形式称为 constexpr if 语句。 如果转换条件的值为假,则第一个子语句是丢弃的语句,否则第二个子语句(如果存在)是丢弃的语句。 在封闭模板化实体 ([temp.pre]) 的实例化期间,如果条件在实例化后不依赖于值,则不会实例化丢弃的子语句(如果有)。

读到人们会认为静态断言会被删除,但事实并非如此。

静态断言在模板的第一阶段被触发,因为编译器知道它总是假的。

来自[temp.res]/8 (强调我的)

可以在任何实例化之前检查模板的有效性。 [注意:知道哪些名称是类型名称允许以这种方式检查每个模板的语法。 尾注] 程序格式错误,无需诊断,如果:

  • (8.1) 不能为模板模板内的 constexpr if 语句的子语句生成有效的特并且模板没有被实例化,或者

[...]

是的,您的False<T>取决于T 问题在于泛型 lambda 本身就是一个模板,并且False<T>不依赖于 lambda 的任何模板参数。

对于一个T的是False<T>是假的,静态断言永远是假的,无论哪个模板参数发送到拉姆达。

编译器可以看到,对于模板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>{});
}

活生生的例子

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM