【问题标题】:Is "if constexpr" useful outside of templates?“if constexpr”在模板之外有用吗?
【发布时间】:2018-12-02 23:28:24
【问题描述】:

我正在尝试完全理解if constexpr

我了解,如果if constexpr(expr) 用在模板中,而expr 依赖于模板参数,那么在实例化过程中,只会实例化then/else 分支中的一个,另一个将被实例化被丢弃。

我有两个问题:

  • 如果expr 不依赖于模板参数,那么if constexpr(expr) 的任何分支都不会被丢弃,这是真的吗?如果是,标准在哪里这样说?我看不出标准在哪里有异常丢弃仅在 expr 依赖时发生。
  • if constexpr 在模板之外有用吗?如果是,这个的用例是什么?你能举一些例子来理解它的用处吗?

【问题讨论】:

  • 我会说是的,因为它可以取代通常使用预处理器的#ifdef 的特征选择结构。
  • @HenriMenke:“问题”是(如我所见),在模板之外,不会丢弃任何分支。所以我真的不明白if constexpr 的意义。一个简单的if 会(几乎)做同样的事情。
  • 只有 MSVC 在没有实例化的情况下才会完全丢弃分支。 godbolt.org/z/Zg1-PB
  • @HenriMenke 即使它从未实例化,分支中的代码仍然必须在语法上有效。但是iirc不需要诊断,所以gcc、clang和MSVC在这里都是正确的……

标签: c++ c++17 constexpr if-constexpr template-instantiation


【解决方案1】:

如果expr 不依赖于模板参数,那么if constexpr(expr) 的任何分支都不会被丢弃,这是真的吗?如果是,标准在哪里这样说? […]

是的,这是真的。您正在寻找[stmt.if]/2。具体这部分:

[…] 在封闭模板化实体的实例化期间,如果条件在其实例化后不依赖于值,则不实例化丢弃的子语句(如果有)。 […]

我能找到的最好的例子是 cppreference.com 给出的实例化后最终依赖于值的情况:

template<class T> void g() {
    auto lm = [](auto p) {
        if constexpr (sizeof(T) == 1 && sizeof p == 1) {
           // this condition remains value-dependent after instantiation of g<T>
        }
    };
}

if constexpr 在模板之外有用吗?如果是,你能举一些例子来理解它的用处吗?

if constexpr 没有出现在模板内时,所有分支都将被实例化,[basic.def.odr]/10 仍然适用:

每个程序都应包含该程序中 在废弃语句之外使用的每个非内联函数或变量的确切定义; […]

强调我的。这实际上意味着在废弃语句中对实体的 odr 使用不计算在内。例如:

void blub();

constexpr bool use_blub = false;

void f()
{
    if constexpr (use_blub)
    {
        blub();
    }
}

如果条件为假,对blub() 的调用将不需要您的程序定义blub()。使用普通的if,程序仍然需要在某处提供blub() 的定义,即使它从未使用过。因此,例如,您可以使用if constexpr 在调用某个库函数和调用某个回退实现之间切换,具体取决于该库是否可用(以及是否被链接到)。除此之外,假设,如果由于if constexpr 而无法访问代码,编译器可能不会警告无法访问的代码,就像普通的if 一样。但是,我无法使用任何实际的编译器想出一个这样的例子……

【讨论】:

  • 感谢您的回答!我怀疑这是我需要的部分。但是,我很难理解“条件在其实例化后不依赖于值”部分。你能解释一下这是什么意思吗?
  • 我可以看到if constexpr很有用,这是编写“通用”代码的另一种方式
  • @geza 我为“初始化后的值依赖”部分添加了一个示例。基本上,值相关意味着条件取决于模板参数(通常是 if constexpr 的情况)。在某些情况下,例如,在嵌套模板中,包含 if constexpr 的代码将在外部模板的实例化期间被实例化,但条件还不能被评估,因为它仍然依赖于内部模板参数......
  • 谢谢!我会暂时搁置这个问题,也许有人可以在非价值依赖的上下文中给出if constexpr 的有用示例。
  • @MooingDuck:你能举个例子吗?
猜你喜欢
  • 2022-01-10
  • 2019-02-20
  • 1970-01-01
  • 2021-11-21
  • 1970-01-01
  • 2017-09-12
  • 2018-07-10
  • 1970-01-01
相关资源
最近更新 更多