template<typename T>
auto length(const T& value) noexcept {
if (std::integral<T>::value) { // is number
return value;
else
return value.length();
}
int main() noexcept {
int a = 5;
std::string b = "foo";
std::cout << length(a) << ' ' << length(b) << '\n'; // doesn't compile
}
错误信息:
main.cpp: In instantiation of 'auto length(const T&) [with T = int]':
main.cpp:16:26: required from here
main.cpp:9:16: error: request for member 'length' in 'val', which is of non-class type 'const int'
return val.length();
~~~~^~~~~~
这是因为当编译器示例化length时,函数将如下所示:
auto length(const int& value) noexcept {
if (std::is_integral<int>::value) { // is number
return value;
else
return value.length();
}
2条答案
按热度按时间lokaqttq1#
唯一的区别是
if constexpr
是在编译时计算的,而if
不是。这意味着分支可以在编译时被拒绝,因此永远不会被编译。假设你有一个函数
length
,它返回一个数字的长度,或者一个具有.length()
函数的类型的长度。你不能在一个函数中完成它,编译器会抱怨:错误信息:
这是因为当编译器示例化
length
时,函数将如下所示:value
是一个int
,因此没有length
成员函数,因此编译器会抱怨。编译器无法看到int
永远不会到达该语句,但这并不重要,因为编译器无法保证这一点。现在你可以专门化
length
,但是对于很多类型(比如这个例子-每个数字和类都有一个length
成员函数),这会导致很多重复的代码。SFINAE也是一种解决方案,但它需要多个函数定义,这使得代码比下面需要的要长得多。使用
if constexpr
而不是if
意味着分支(std::is_integral<T>::value
)将在编译时被评估,如果它是true
,那么其他分支(else if
和else
)将被丢弃。如果是false
,则检查下一个分支(这里是else
),如果是true
,则丢弃每隔一个分支,依此类推。现在,当编译器示例化
length
时,它看起来像这样:因此这两个重载是有效的,代码将成功编译。
sqougxex2#
普通的
if
语句:if constexpr
语句: