if constexpr的False分支未在模板化lambda中丢弃
False-branch of if constexpr not discarded in templated lambda
我在模板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);
那么错误分支不会被丢弃,编译器会给我
'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);
}
根据链接的代码,
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;
都是格式错误的;即,无论CCD_ 7的值是多少,它总是不成形的。
注意:对于所有可能的特殊化,丢弃的语句不能格式错误:
这种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;
}
并将其用作
foo_bar<no> obj = {};
print_fun<no>(obj);
现在对于obj.y
,obj
的类型是foo_bar<condition>
,这取决于模板参数condition
。
实时
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- C++从其他 constexpr 创建 lambda 不能按顺序执行 Constexpr
- 为什么我不能在 constexpr lambda 函数中使用 std::tuple
- 如果在 lambda 中使用 Constexpr static_assert,哪个编译器是正确的?
- 通过 lambda 定义的 constexpr 递归函数
- 在通用 lambda 中使用 constexpr-if 来确定参数的类型
- 如果 Constexpr 在 lambda 中,则编译器行为不同
- lambda 表达式中引用捕获的 constexpr 变量和非显式捕获的 constexpr 变量之间的区别
- 如果递归通用 lambda 中的 constexpr:不同的编译器行为
- "如果 constexpr",在 lambda 内部,在包扩展内部 - 编译器错误?
- 我可以在模板参数中声明一个 constexpr lambda 吗?
- Constexpr lambda argument
- Clang声称通用lambda参数的constexpr成员不是constexpr
- 海湾合作委员会和Clang在lambda的constexpr-ness上存在分歧?
- 为什么这个嵌套的 lambda 不被认为是 constexpr?
- 'if constexpr branch'不会在模板函数内的 lambda 中被丢弃
- 静态(可能是constexpr)数据成员lambda
- lambda内部捕获的constexpr变量失去了其constexpr-ness
- 我可以将C 17 Capture lambda ConstexPR转换操作符的结果用作函数指针模板非类型参数吗?
- constexpr lambda实施 - 该如何工作