11

我对模板化 lambda 中的“if constexpr”有疑问。为了争论,让我们忽略我是如何到达那里的,但是我有一个以某种方式定义的 struct 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 参数 to 与 to相同,则实例化此函数并使用它将编译print_fun,即

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

这确实可以编译,因为错误分支在模板化实体中被丢弃,因此在 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);

然后不丢弃错误分支,编译器给我

'b': 不是 'foo' 的成员

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

用 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);
}
4

1 回答 1

7

根据链接的代码,

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

问题在于,如果使用 constexpr,则该语句std::cout << obj.y << std::endl;对于模板的每个可能实例化都是不正确的print_fun;即,无论condition它的价值是什么,它总是格式不正确。

注意:对于每个可能的专业化,被丢弃的语句不能是格式错误的:

这种包罗万象的语句的常见解决方法是依赖于类型的表达式,该表达式始终为假:

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

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.yobj是类型foo_bar<condition>,这取决于模板参数condition

居住

于 2017-10-29T14:28:21.310 回答