c++ - if constexpr 的假分支未在模板化 lambda 中丢弃

标签 c++ templates lambda c++17 if-constexpr

我对模板化 lambda 中的“if constexpr”有疑问。为了争论起见,让我们忽略我是如何到达那里的,但我有一个以某种方式定义的结构 foo,结果如下:

template<bool condition>
struct foo {
    int a;

    // Only contains b if condition is true
    int b;
}

现在我可以定义一个模板函数 thtemplate

template<bool condition>
void print_fun(foo & obj) {
    /* Do something with obj.a */
    if constexpr(condition)
        /* Do something with obj.b */
};

如果 foo 的 constexpr 参数与 print_fun 的参数相同,即

constexpr bool no = false;
foo<no> obj = {};
print_fun<no>(obj);

这确实可以编译,因为 false 分支在模板实体中被丢弃,因此在 print_fun 中使用 obj.b 没有问题。

但是,如果我定义一个类似的lambda表达式如下:

template<bool condition>
auto print_lambda = [](foo & obj) {
    /* Do something with obj.a */
    if constexpr(condition)
        /* Do something with obj.b */
};

并实例化它:

constexpr bool no = false;
foo<no> obj = {};
print_lambda<no>(obj);

然后 false 分支没有被丢弃,编译器给我

'b': is not a member of 'foo'

这是预期的行为吗,它会发生在其他编译器上吗? 难道我做错了什么? 还是编译器中的错误? (Microsoft Visual Studio 版本 15.4.1,gcc 7.2)

查看我的测试 here使用 gcc,它也不会针对仿函数或函数进行编译。

编辑: 这是我的最小示例的代码,我不知道外部链接是不够的。这在 Visual Studio 15.4.1 上编译,但注释行除外。 foo_bar 在我的描述中取代了 foo

#include <iostream>

constexpr bool no = false;

struct foo {
    int x;
};

struct bar {
    int y;
};

template <bool, typename AlwaysTy, typename ConditionalTy>
struct Combined : AlwaysTy {};

template <typename AlwaysTy, typename ConditionalTy>
struct Combined<true, AlwaysTy, ConditionalTy> : AlwaysTy, ConditionalTy {};

using foo_bar = Combined<no, foo, bar>;

template<bool condition>
void print_fun(foo_bar & obj) {
    std::cout << obj.x << std::endl;
    if constexpr(condition)
        std::cout << obj.y << std::endl;
};

template<bool condition>
auto print_lambda = [](foo_bar & obj) {
    std::cout << obj.x << std::endl;
    if constexpr(condition)
        std::cout << obj.y << std::endl;
};

int main(int argc, char ** argv) {
    foo_bar obj = {};
    print_lambda<no>(obj); // Does not compile
    print_fun<no>(obj);
}

最佳答案

根据链接的代码,

template<bool condition>
void print_fun(foo_bar & obj) {
    std::cout << obj.x << std::endl;
    if constexpr(condition)
        std::cout << obj.y << std::endl;
}

问题出在if constexpr正在使用,声明std::cout << obj.y << std::endl;对于模板的每个可能实例化都是错误的 print_fun ;即无论condition 的值(value)是多少|它总是格式错误。

Note: the discarded statement can't be ill-formed for every possible specialization:

The common workaround for such a catch-all statement is a type-dependent expression that is always false:

要修复它,您可以使语句依赖于模板参数,例如

template <bool condition>
using foo_bar = Combined<condition, foo, bar>;

template<bool condition>
void print_fun(foo_bar<condition> & obj) {
    std::cout << obj.x << std::endl;
    if constexpr(condition)
        std::cout << obj.y << std::endl;
}

并将其用作

foo_bar<no> obj = {};
print_fun<no>(obj);

现在 obj.y , obj类型为 foo_bar<condition> ,这取决于模板参数 condition .

LIVE

关于c++ - if constexpr 的假分支未在模板化 lambda 中丢弃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47000914/

相关文章:

lambda - 如何切换提供者无服务器框架?

php - 一起使用 c++ 和 php

php - 文件写入在 PHP 扩展 c/c++ (linux) 中不起作用

c++ - 串口传输错误如何解决?

c++ - 令人困惑的部分模板特化

java - Lambda 表达式和通用接口(interface)

c++ - 使用宏访问 C 中的结构成员名称

css - 如何在 Joomla 2.5 模板中组织 css 文件?

Java通过替换复制xml节点和子节点

c# - 将 .net Func<T> 转换为 .net Expression<Func<T>>