问题描述
#include <type_traits>
#include <iostream>
int main() {
struct A { int i = 123; };
struct B { int j = 456; };
B x;
if constexpr(std::is_same_v<decltype(x),A>)
std::cout << "A: " << x.i;
else if constexpr(std::is_same_v<decltype(x),B>)
std::cout << "B: " << x.j;
}
通过这段代码,我希望针对不同类型有几个不同的代码分支。一般来说,我不仅需要针对特定类型而且针对任何 constexpr 条件的不同分支。
上面的代码是不可编译的,因为看起来编译器总是试图编译所有 if-constexpr 分支,即使它们有编译时错误条件。
当然,我可以通过使用模板结构特化来解决上面的任务,就像下面的可编译代码一样:
#include <type_traits>
#include <iostream>
template <size_t Id>
struct Code;
template <>
struct Code<0> {
template <typename AT>
void operator()(AT & x){
std::cout << "A: " << x.i;
}
};
template <>
struct Code<1> {
template <typename BT>
void operator()(BT & x){
std::cout << "B: " << x.j;
}
};
int main() {
struct A { int i = 123; };
struct B { int j = 456; };
B x;
Code<std::is_same_v<decltype(x),A> ? 0 : std::is_same_v<decltype(x),B> ? 1 : -1>()(x);
}
但最后一个解决方案有几个缺点 - 1)它更加冗长,需要更多的代码行。 2)需要全局定义代码结构,因为模板结构只能全局定义。 3) 它需要所有需要的代码参数才能传递/转发到 operator() 调用。
constexpr 变体看起来更优雅,使用起来更直观。有没有办法用 if-constexpr 解决这样的任务?强制编译器不编译 compile-time-false-branch。
解决方法
正如评论中提到的,"you have to make the discarded statement dependent of the template parameters" - 如果不引入模板,您尝试做的事情是不可能的。
例如,这可以“工作”,但远不是一个好的解决方案。我将其添加为答案,因为与我标记为重复的问题的相似性存在争议。
#include <type_traits>
#include <iostream>
int main() {
struct A { int i = 123; };
struct B { int j = 456; };
B x;
[](auto const & x) {
if constexpr(std::is_same_v<std::remove_cvref_t<decltype(x)>,A>) {
std::cout << "A: " << x.i;
} else if constexpr(std::is_same_v<std::remove_cvref_t<decltype(x)>,B>) {
std::cout << "B: " << x.j;
}
}(x);
}