我的問題是為什么以下代碼是有效的 C :
#include <iostream>
#include <tuple>
#include <type_traits>
std::tuple<const char *, const char *> tuple("Hello", "world");
std::integral_constant<std::size_t, 0> zero;
std::integral_constant<std::size_t, 1> one;
template<typename T> const char *
lookup(T n)
{
// I would expect to have to write this:
// return std::get<decltype(n)::value>(tuple);
// But actually this works:
return std::get<n>(tuple);
}
int
main()
{
std::cout << lookup(zero) << " " << lookup(one) << std::endl;
}
當然,我很高興能夠以這種方式編程。此外,據我所知,它std::integral_constant有一個constexpr轉換運算子。但是,nto的引數lookup不是 constexpr,所以我對非 constexpr 物件上的非靜態方法(即使方法本身是 constexpr)如何可能回傳編譯時常量感到困惑。
當然,我們碰巧知道在這種情況下轉換運算子的主體不查看運行時值,但型別簽名中沒有任何東西可以保證這一點。例如,以下型別顯然不起作用,即使它也有一個 constexpr 轉換運算子:
struct bad_const {
const std::size_t value;
constexpr bad_const(std::size_t v) : value(v) {}
constexpr operator std::size_t() const noexcept { return value; }
};
bad_const badone(1);
如果它們忽略隱式引數,是否有一些額外的方法屬性被認為是不同的this?
uj5u.com熱心網友回復:
當然,我們碰巧知道在這種情況下轉換運算子的主體不查看運行時值,但型別簽名中沒有任何東西可以保證這一點。
正確的。您缺少的是這無關緊要的事實。
在常量運算式求值期間呼叫函式時,編譯器會檢查該函式是否為constexpr. 如果不是constexpr,則封閉評估無法產生常量運算式。
但如果是 constexpr,則編譯器在編譯時執行其主體并檢查其主體中是否有任何內容使封閉的評估不符合常量運算式的資格。
因此,在 的轉換運算子的情況下std::integral_constant,編譯器在編譯時執行其主體,看到它只是回傳模板引數的值,這很好。
如果編譯器正在評估constexpr某個其他型別的成員函式,該函式讀取物件的const非非靜態資料成員(并且物件不是constexpr),那么編譯器此時將確定封閉的評估不是一個常量運算式。
有點令人不安的是,當您看到一個已宣告的函式時constexpr,這并不能告訴您該函式的哪些評估會產生常量運算式,但事實就是如此。
uj5u.com熱心網友回復:
在需要是一個std::get<n>()但你通過了一個。所以編譯器檢查是否存在從一個到另一個的隱式轉換,它試圖呼叫. 碰巧這正是您擁有的運營商。所以一切都很好。nsize_tstd::integral_constant<...>std::integral_constant<...>::operator size_t()std::integral_constant<std::size_t, 0> zero;
但是你問為什么這是一個編譯時常量:operator size_t()回傳static constexpr T value = v;. 因此,它integral_constant本身是否為 const 并不重要。它對回傳的常數沒有影響。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/476406.html
