問題描述
if constexpr()
和 if()
有什么區別?
我可以在何時何地同時使用它們?
Where and When can I use both of them?
推薦答案
唯一的區別是 if constexpr
在編譯時被評估,而 if
不是.這意味著分支可以在編譯時被拒絕,因此永遠不會被編譯.
The only difference is that if constexpr
is evaluated at compile time, whereas if
is not. This means that branches can be rejected at compile time, and thus will never get compiled.
假設你有一個函數,length
,它返回一個數字的長度,或者一個具有 .length()
函數的類型的長度.你不能在一個函數中做到,編譯器會抱怨:
Imagine you have a function, length
, that returns the length of a number, or the length of a type that has a .length()
function. You can't do it in one function, the compiler will complain:
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) << '
'; // 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
時,函數會是這樣的:
That's because when the compiler instantiates length
, the function will look like this:
auto length(const int& value) noexcept {
if (std::is_integral<int>::value) { // is number
return value;
else
return value.length();
}
value
是一個 int
,因此沒有 length
成員函數,因此編譯器會抱怨.編譯器看不到 int
永遠不會到達該語句,但這無關緊要,因為編譯器無法保證.
value
is an int
, and as such doesn't have a length
member function, and so the compiler complains. The compiler can't see that statement will never be reached for an int
, but it doesn't matter, as the compiler can't guarantee that.
現在你可以特化 length
,但是對于很多類型(比如在這種情況下 - 每個數字和具有 length
成員函數的類),這會導致很多重復的代碼.SFINAE 也是一個解決方案,但是它需要多個函數定義,這使得代碼比下面需要的要長很多.
Now you can either specialize length
, but for a lot of types (like in this case - every number and class with a length
member function), this results in a lot of duplicated code. SFINAE is also a solution, but it requires multiple function definitions, which makes the code a lot longer than it needs to be compared to the below.
使用 if constexpr
而不是 if
意味著分支 (std::is_integral
) 將在編譯時間,如果它是 true
,那么所有其他分支(else if
和 else
)都會被丟棄.如果是false
,則檢查下一個分支(這里是else
),如果是true
,則丟棄所有其他分支,依此類推...
Using if constexpr
instead of if
means that the branch (std::is_integral<T>::value
) will get evaluated at compile time, and if it is true
then every other branch (else if
and else
) gets discarded. If it is false
, the next branch is checked (here else
), and if it is true
, discard every other branch, and so on...
template<typename T>
auto length(const T& value) noexcept {
if constexpr (std::integral<T>::value) { // is number
return value;
else
return value.length();
}
現在,當編譯器實例化length
時,它看起來像這樣:
Now, when the compiler will instantiate length
, it will look like this:
int length(const int& value) noexcept {
//if (std::is_integral<int>::value) { this branch is taken
return value;
//else discarded
// return value.length(); discarded
}
std::size_t length(const std::string& value) noexcept {
//if (std::is_integral<int>::value) { discarded
// return value; discarded
//else this branch is taken
return value.length();
}
所以這 2 個重載是有效的,代碼將成功編譯.
And so those 2 overloads are valid, and the code will compile successfully.
這篇關于“if constexpr()"之間的區別與“if()"的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!