C++ if constexpr的用法(非常详细)
C++ 中,当使用 SFINAE 和 std::enable_if 来定义函数重载或编写可变参数函数模板时,模板元编程可能变得复杂和混乱。C++17 的一个特性就是为了简化这类代码而提出的,它被称为 if constexpr,它定义了一个 if 语句,该语句的条件在编译时进行计算,导致编译器选择编译单元中的分支或其他分支的主体。
if constexpr 的典型用法是简化可变参数模板和 std::enable_if 的代码。
下面我们将探讨使用 if constexpr 进行条件编译的几个用例。使用 if constexpr 语句完成以下操作:
1) 避免使用 std::enable_if 和依赖 SFINAE 对函数模板类型施加限制并有条件地编译代码:
2) 简化可变参数模板的编写,实现编译时递归元编程:
然而,如果没有 if constexpr 的帮助,我们只能使用 std::enable_if 来实现它。下面的实现是一个更糟糕的替代方案:
if constexpr 的典型用法是简化可变参数模板和 std::enable_if 的代码。
C++ if constexpr的使用方式
if constexpr 的语法与常规的 if 语句非常类似,并且要求在条件之前使用 constexpr 关键字。一般形式如下:if constexpr (init-statement condition) statement-true else statement-falseif 语句中的条件必须是一个编译时表达式,该表达式的计算值为布尔值或可转换为布尔值。如果条件为 true,则选择 if 语句的主体,这意味着它将在编译单元中结束;如果条件为 false,则计算 else 分支(如果定义了分支)。
下面我们将探讨使用 if constexpr 进行条件编译的几个用例。使用 if constexpr 语句完成以下操作:
1) 避免使用 std::enable_if 和依赖 SFINAE 对函数模板类型施加限制并有条件地编译代码:
template <typename T>
auto value_of(T value)
{
if constexpr (std::is_pointer_v<T>)
return *value;
else
return value;
}
2) 简化可变参数模板的编写,实现编译时递归元编程:
namespace binary
{
using byte8 = unsigned char;
namespace binary_literals
{
namespace binary_literals_internals
{
template <typename CharT, char d, char... bits>
constexpr CharT binary_eval()
{
if constexpr(sizeof...(bits) == 0)
return static_cast<CharT>(d-'0');
else if constexpr(d == '0')
return binary_eval<CharT, bits...>();
else if constexpr(d == '1')
return static_cast<CharT>(
(1 << sizeof...(bits)) |
binary_eval<CharT, bits...>());
}
}
template<char... bits>
constexpr byte8 operator"""_b8()
{
static_assert(
sizeof...(bits) <= 8,
"binary literal b8 must be up to 8 digits long");
return binary_literals_internals::
binary_eval<byte8, bits...>();
}
}
}
C++ if constexpr的工作原理
在前文的第一个例子中,value_of() 函数模板有一个整洁的签名,函数体也很简单。如果替换模板形参的类型是指针类型,编译器将选择第一个分支(即 return*value;)来生成代码,并丢弃 else 分支。对于非指针类型,因为条件的计算结果为 false,编译器将选择 else 分支(即 return value;)来生成代码,并丢弃其余部分。该函数的使用方法如下:auto v1 = value_of(42); auto p = std::make_unique<int>(42); auto v2 = value_of(p.get());
然而,如果没有 if constexpr 的帮助,我们只能使用 std::enable_if 来实现它。下面的实现是一个更糟糕的替代方案:
template <typename T, typename = typename std::enable_if_t<std::is_pointer_v<T>, T>>
auto value_of(T value)
{
return *value;
}
template <typename T, typename = typename std::enable_if_t<!std::is_pointer_v<T>, T>>
T value_of(T value)
{
return value;
}
如你所见,if constexpr 变体不仅更短,而且更有表现力,更容易阅读和理解。
ICP备案:
公安联网备案: