我在模板化的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参数相同,那么实例化该函数并使用它将进行编译,即
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':不是'foo'的成员
这是预期的行为,是否会在其他编译器上发生? 难道我做错了什么? 或者它是编译器中的错误? (Microsoft Visual Studio版本15.4.1,gcc 7.2)
使用gcc检查我的测试here,它也不能为编译器或函数编译。
编辑:
这是我最小例子的代码,我不知道外部链接是不够的。这在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);
}
答案 0 :(得分: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;
}
问题在于使用了if 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;
}
并将其用作
foo_bar<no> obj = {};
print_fun<no>(obj);
现在,对于obj.y
,obj
的类型为foo_bar<condition>
,具体取决于模板参数condition
。