constexpr if 和 static_assert

2021-12-13 00:00:00 templates c++ c++17 constexpr static-assert

P0292R1 constexpr if 已经包括,C++17 正轨.它看起来很有用(并且可以替代 SFINAE 的使用),但是关于 static_assert 在错误分支中格式错误,不需要诊断 的评论让我感到害怕:

P0292R1 constexpr if has been included, on track for C++17. It seems useful (and can replace use of SFINAE), but a comment regarding static_assert being ill-formed, no diagnostic required in the false branch scares me:

Disarming static_assert declarations in the non-taken branch of a
constexpr if is not proposed.

void f() {
  if constexpr (false)
    static_assert(false);   // ill-formed
}

template<class T>
void g() {
  if constexpr (false)
    static_assert(false);   // ill-formed; no 
               // diagnostic required for template definition
}

我认为在 constexpr if 中使用 static_assert 是完全禁止的(至少是 false/non-taken 分支,但这实际上意味着它不是一个安全或有用的事情).

I take it that it's completely forbidden to use static_assert inside constexpr if (at least the false / non-taken branch, but that in practice means it's not a safe or useful thing to do).

这是如何从标准文本中得出的?我发现提案措辞中没有提到 static_assert,并且 C++14 constexpr 函数确实允许 static_assert(cppreference 中的详细信息:constexpr).

How does this come about from the standard text? I find no mentioning of static_assert in the proposal wording, and C++14 constexpr functions do allow static_assert (details at cppreference: constexpr).

是不是藏在这个新句子里(6.4.1之后)?:

Is it hiding in this new sentence (after 6.4.1) ? :

当 constexpr if 语句出现在模板化实体中时,在封闭模板或通用 lambda 的实例化期间,丢弃的语句不会被实例化.

When a constexpr if statement appears in a templated entity, during an instantiation of the enclosing template or generic lambda, a discarded statement is not instantiated.

从那时起,我假设也禁止调用其他 constexpr(模板)函数,这些函数在调用图的某处可能会调用 static_assert.

From there on, I assume that it is also forbidden, no diagnostic required, to call other constexpr (template) functions which somewhere down the call graph may call static_assert.

底线:

如果我的理解是正确的,这是否对 constexpr if 的安全性和实用性施加了相当严格的限制,因为我们必须(从文档或代码检查中)了解任何使用static_assert?我的担心是不是放错地方了?

If my understanding is correct, doesn't that put a quite hard limit on the safety and usefulness of constexpr if as we would have to know (from documentation or code inspection) about any use of static_assert? Are my worries misplaced?

更新:

此代码编译时没有警告(clang head 3.9.0)但据我所知格式错误,不需要诊断.有效与否?

This code compiles without warning (clang head 3.9.0) but is to my understanding ill-formed, no diagnostic required. Valid or not?

template< typename T>
constexpr void other_library_foo(){
    static_assert(std::is_same<T,int>::value);
}

template<class T>
void g() {
  if constexpr (false)
    other_library_foo<T>(); 
}

int main(){
    g<float>();
    g<int>();
}

推荐答案

这是关于模板的一个完善的规则――同样的规则允许编译器诊断templatevoid f() { 返回 1;}.[temp.res]/8 新更改加粗:

This is talking about a well-established rule for templates - the same rule that allows compilers to diagnose template<class> void f() { return 1; }. [temp.res]/8 with the new change bolded:

程序格式错误,无需诊断,如果:

The program is ill-formed, no diagnostic required, if:

  • 不能为模板或子语句生成有效的特化constexpr if 语句 ([stmt.if]) 中的模板并且模板没有被实例化,或者
  • [...]
  • no valid specialization can be generated for a template or a substatement of a constexpr if statement ([stmt.if]) within a template and the template is not instantiated, or
  • [...]

不能为包含 static_assert 的模板生成有效的特化,其条件是非依赖的并且计算结果为 false,因此该程序是格式错误的 NDR.

No valid specialization can be generated for a template containing static_assert whose condition is nondependent and evaluates to false, so the program is ill-formed NDR.

static_assert 的依赖条件可以评估为至少一种类型的 true 不受影响.

static_asserts with a dependent condition that can evaluate to true for at least one type are not affected.

相关文章