如果constexpr没有丢弃在模板化的lambda中的假分支

Han*_*sch 10 c++ lambda templates c++17 if-constexpr

我在模板化的lambda中遇到"if constexpr"的问题.为了论证,让我们忽略我是如何到达那里的,但我有一个结构foo,它以某种方式定义,产生如下内容:

template<bool condition>
struct foo {
    int a;

    // Only contains b if condition is true
    int b;
}
Run Code Online (Sandbox Code Playgroud)

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

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

实例化这个功能,并使用它会编译,如果constexpr参数foo是一样的一个print_fun,即

constexpr bool no = false;
foo<no> obj = {};
print_fun<no>(obj);
Run Code Online (Sandbox Code Playgroud)

这会编译,因为假分支在模板化实体内被丢弃,因此在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 */
};
Run Code Online (Sandbox Code Playgroud)

并实例化它:

constexpr bool no = false;
foo<no> obj = {};
print_lambda<no>(obj);
Run Code Online (Sandbox Code Playgroud)

那么假分支不会丢弃,编译器会给我

'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);
}
Run Code Online (Sandbox Code Playgroud)

son*_*yao 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;
}
Run Code Online (Sandbox Code Playgroud)

问题在于如果使用constexpr,则该语句std::cout << obj.y << std::endl;对于模板的每个可能的实例化都是错误的print_fun; 也就是说无论condition它的价值是什么,它总是形成不良的.

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

这种catch-all语句的常见解决方法是依赖于类型的表达式,该表达式始终为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;
}
Run Code Online (Sandbox Code Playgroud)

并用它作为

foo_bar<no> obj = {};
print_fun<no>(obj);
Run Code Online (Sandbox Code Playgroud)

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

生活