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

标签 c++ templates language-lawyer c++17 static-assert

当我们想使用 static_assertif 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/

相关文章:

c++ - 尝试进行一些规范化并不断出错

c++ - C++ 模板函数可以选择成员变量吗?

c++ - 什么是微不足道的功能?

c++ - std::is_unsigned<bool>::value 定义是否明确?

c++ - 检查传递给可变参数模板的类型

c++ - 我有两个用 Visual Studio 构建的 Windows C++ 应用程序。现在我想开发一个更新应用程序来更新这些应用程序

c++ - 类成员上的 Decltype 作为模板参数

C++ list<T>::iterator 不能在派生类模板中使用

c++ - 在 C++ 中存储局部变量和临时变量的存储术语是什么?

c++ - 在 C++ 中声明泛型 istream