if constexpr 的假分支未在模板化 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);
这确实可以编译,因为假分支在模板实体中被丢弃,因此在 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);
然后false分支没有被丢弃,编译器给我
'b': is not a member of 'foo'
这是有意为之的行为吗,它会发生在其他编译器上吗?
难道我做错了什么?
还是编译器中的错误? (微软 Visual Studio 版本 15.4.1,gcc 7.2)
用 gcc 查看我的测试 here,它也没有为仿函数或函数编译。
编辑:
这是我的最小示例的代码,我不知道外部 link 是不够的。这在 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;
}
问题在于使用了 if constexpr,语句 std::cout << obj.y << std::endl;
对于模板 print_fun
的每个可能实例都是错误的;即无论 condition
的值是多少,它总是格式错误的。
Note: the discarded statement can't be ill-formed for every possible specialization:
The common workaround for such a catch-all statement is a type-dependent expression that is always 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 中遇到 "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);
这确实可以编译,因为假分支在模板实体中被丢弃,因此在 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);
然后false分支没有被丢弃,编译器给我
'b': is not a member of 'foo'
这是有意为之的行为吗,它会发生在其他编译器上吗? 难道我做错了什么? 还是编译器中的错误? (微软 Visual Studio 版本 15.4.1,gcc 7.2)
用 gcc 查看我的测试 here,它也没有为仿函数或函数编译。
编辑:
这是我的最小示例的代码,我不知道外部 link 是不够的。这在 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;
}
问题在于使用了 if constexpr,语句 std::cout << obj.y << std::endl;
对于模板 print_fun
的每个可能实例都是错误的;即无论 condition
的值是多少,它总是格式错误的。
Note: the discarded statement can't be ill-formed for every possible specialization:
The common workaround for such a catch-all statement is a type-dependent expression that is always 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
。