雖然模板元編程的想法——盡可能在編譯時計算——非常棒,但我想知道當前的 C 20 特性是否允許我們通過使用、、、、和其他 C 20 特性來constexpr完全consteval避免TMP if constexpr。concept這是真的?還是 TMP 提供的某些功能無法替代?
uj5u.com熱心網友回復:
不,模板元編程不能完全被 C 20 語言實用程式替代;雖然大量可以。
constexpr, consteval, 等等當然有助于減輕傳統上使用 TMP 完成的事情的負擔(這些年來越來越多的情況),但模板仍然服務于型別確定的正交目的,更重要的是,型別生成.
constexpr/ consteval/etc 的表達能力有限,因為這些函式的引數本身不是常量運算式。即使在consteval函式中也是如此,盡管它只能在編譯時運行。這意味著以下內容不是合法的 C :
template <typename T>
consteval auto make_array(std::size_t n) {
return std::array<T,n>{};
// ^ - error, 'n' is not a constant expression
}
Live example
這種限制意味著更復雜的生成仍然需要傳統的模板元編程技術。這在嘗試產生可變引數擴展時尤其必要。
(如評論中所述,這也將阻止在決議字串時生成適當的型別)。
例如,考慮std::index_sequence不使用內部函式的實作會是什么樣子。make_index_sequence<N>擴展為的天真實作index_sequence<0, 1, 2, ..., N-1>看起來像這樣:
template <std::size_t... Ints>
struct index_sequence
{
static constexpr std::size_t size() noexcept { return sizeof...(Ints); }
};
namespace detail {
template <bool End, std::size_t N, std::size_t...Tails>
struct make_index_sequence_impl
: make_index_sequence_impl<((N-1) == 0u), N-1, N-1, Tails...>{};
template <std::size_t N, std::size_t...Tails>
struct make_index_sequence_impl<true, N, Tails...>
: std::type_identity<index_sequence<Tails...>>{};
} // namespace detail
template <std::size_t N>
using make_index_sequence = typename detail::make_index_sequence_impl<(N==0u), N>::type;
Live Example
從技術上講,這個index_sequence例子可以用 C 20 撰寫,帶有回傳一個實體的遞回consteval函式index_sequence——但這只是因為我們可以將一個值傳遞給一個模板推導的函式。更復雜的型別示例在編譯時不會有這種奢侈。
一般來說,像這樣更復雜的型別生成將需要一定程度的 TMP,特別是如果型別對默認可構造性有限制,或者本身不能是常量運算式。在這種情況下,這將需要部分模板專業化,這開始屬于一般模板元編程實踐。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/428014.html
下一篇:使模板函式反映其模板引數的簽名
