如果在模板化的lambda中不丢弃constexpr的错误分支 [英] False-branch of if constexpr not discarded in templated lambda

查看:101
本文介绍了如果在模板化的lambda中不丢弃constexpr的错误分支的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在模板化的lambda中,"if constexpr"有问题.为了争辩,让我们忽略我如何到达那里,但是我有一个struct foo,它以某种方式定义,结果如下:

I have a problem with "if constexpr" in a templated lambda. For the sake of argument let's ignore how I got there, but I have a struct foo that is defined in some way to result in something as follows:

template<bool condition>
struct foo {
    int a;

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

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

Now I can define a templated function 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参数相同,即

,则实例化此函数并使用该函数将进行编译.

Instantiating this function and using it will compile, if the constexpr parameter to foo is the same as the one to print_fun, i.e.

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

之所以编译,是因为在模板实体中丢弃了false分支,因此在print_fun内使用obj.b没有问题.

This does compile because the false branch is discarded inside a templated entity, and thus there is no problem with using obj.b inside print_fun.

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

However, if I define a similar lambda expression as follows:

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分支,编译器给我

then the false branch is not discarded and the compiler gives me

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

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

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

Is this intended behavior, does it happen on other compilers? Am I doing something wrong? Or is it a bug in the compiler? (Microsoft Visual Studio Version 15.4.1, gcc 7.2)

使用gcc在此处进行测试,该测试也无法针对函子或函数进行编译.

Check out my test here with gcc, where it does not compile for a functor or function either.

这是我最小示例的代码,我不知道外部链接不够用.除注明的行外,此版本均在Visual Studio 15.4.1上编译. 在我的描述中,foo_bar代替了foo.

Here is the code of a my minimal example, I was not aware that the external link wouldn't suffice. This compiles on Visual Studio 15.4.1, except for the noted line. foo_bar takes the place of foo in my description.

#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;
}

问题出在如果使用constexpr ,则该语句对于模板print_fun的每个可能实例,std::cout << obj.y << std::endl;的格式均不正确;也就是说,无论condition的值是多少,它总是格式错误.

The problem is with if constexpr being used, the statement std::cout << obj.y << std::endl; is ill-formed for every possible instantiation of the template print_fun; i.e. no matter what's the value of condition it's just always ill-formed.

注意:对于所有可能的专业化,废弃的语句都不会格式错误:

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

这种包罗万象的语句的常见解决方法是始终为false的类型相关表达式:

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

要解决此问题,您可以使语句依赖于模板参数,例如

To fix it you can make the statement to dependent on the template parameter, e.g.

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.

Now for obj.y, obj is of type foo_bar<condition>, which depends on the template parameter condition.

实时

这篇关于如果在模板化的lambda中不丢弃constexpr的错误分支的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆