如果在模板化的lambda中不丢弃constexpr的错误分支 [英] False-branch of if constexpr not discarded in templated lambda
问题描述
在模板化的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.y
的obj
类型为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屋!