随着if constexpr
的引入在 c++17
,在 c++14
中使用编译时 SFINAE 解决的一些问题/c++11
现在可以使用 if constexpr
解决, 语法更简单。
例如,考虑以下编译时递归的基本示例,以生成打印可变数量参数的子例程。
#include <iostream>
#include <type_traits>
template <typename T>
void print_sfinae(T&& x)
{
std::cout << x << std::endl;
}
template <typename T0, typename... T>
std::enable_if_t<(sizeof...(T) > 0)> print_sfinae(T0&& x, T&&... rest)
{
std::cout << x << std::endl;
print_sfinae(std::forward<T>(rest)...);
}
template <typename T0, typename... T>
void print_ifconstexpr(T0&&x, T&&... rest)
{
if constexpr (sizeof...(T) > 0)
{
std::cout << x << std::endl;
print_ifconstexpr(std::forward<T>(rest)...);
}
else
std::cout << x << std::endl;
}
int main()
{
print_sfinae(5, 2.2, "hello");
print_ifconstexpr(5, 2.2, "hello");
return 0;
}
例程print_sfinae
使用来自 c++11
的 SFINAE 技术,而 print_ifconstexpr
使用 if constexpr
做同样的工作.
可以假设编译器在计算 if constexpr
时完全丢弃未验证条件,只为满足 if constexpr
的分支生成代码健康)状况?标准是否为编译器指定了这样的行为?
更一般地说,就效率和生成的代码而言,是基于if constexpr
的解决方案。是否与基于 pre-c++17 SFINAE 的等效解决方案相同?
最佳答案
Can one assume that the compiler, on evaluating the
if constexpr
completely discards the non-verified condition and generate code only for the branch which satisfy theif constexpr
condition? Does the standard specifies such a behavior for the compiler?
标准规定,从[stmt.if] :
If the
if
statement is of the formif constexpr
, the value of the condition shall be a contextually converted constant expression of typebool
; this form is called a constexpr if statement. If the value of the converted condition isfalse
, the first substatement is a discarded statement, otherwise the second substatement, if present, is a discarded statement. During the instantiation of an enclosing templated entity, if the condition is not value-dependent after its instantiation, the discarded substatement (if any) is not instantiated.
这里的要点是丢弃语句未实例化 - 这就是 if constexpr
作为语言特性的全部目的,允许您编写:
template <typename T0, typename... T>
void print_ifconstexpr(T0&& x, T&&... rest)
{
std::cout << x << std::endl;
if constexpr (sizeof...(T) > 0) {
print_ifconstexpr(std::forward<T>(rest)...);
}
}
你不能用简单的 if
来做到这一点,因为那仍然需要实例化子语句 - 即使条件可以在编译时确定为 false
.一个简单的 if
需要调用 print_ifconstexpr()
的能力。
if constexpr
将不会实例化递归调用,除非 rest...
中有内容,所以这是有效的。
其他一切都是因为没有实例化。丢弃的语句不能有任何生成的代码。
if constexpr
形式更容易编写,更容易理解,当然编译速度也更快。绝对喜欢它。
请注意,您的第一个示例根本不需要 SFINAE。这很好用:
template <typename T>
void print(T&& x)
{
std::cout << x << std::endl;
}
template <typename T0, typename... T>
void print(T0&& x, T&&... rest)
{
std::cout << x << std::endl;
print(std::forward<T>(rest)...);
}
同样:
void print() { }
template <typename T0, typename... T>
void print(T0&& x, T&&... rest)
{
std::cout << x << std::endl;
print(std::forward<T>(rest)...);
}
关于c++ - 如果 constexpr 与 sfinae,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54065446/