模板元编程是否完全能够在 C++20 中被替代?

Is template metaprogramming fully able to be substituted in C++20?

虽然模板元编程的想法——尽可能在编译时计算一些东西——很棒,但我想知道当前的 C++20 特性是否允许我们通过使用 constexpr、[=11 来完全避免 TMP =]、if constexprconcept 和其他 C++20 特性。这是真的?还是TMP提供的某些功能无法替代?

,模板元编程不能完全被C++20语言实用程序取代;虽然大量可以。

constexprconsteval 等当然都有助于减轻传统上使用 TMP 完成的事情的负担(多年来这种情况越来越多),但模板仍然可以使用type-determination 的正交目的,更重要的是,type-generation.

constexpr/consteval/etc 的表达能力受到限制,因为此类函数的参数本身并不是常量表达式。即使在 consteval 函数中也是如此,尽管事实上这只能在 compile-time 中 运行。这意味着以下是不合法的 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

此限制意味着更复杂的生成仍然需要传统的 template-metaprogramming 技术。这在尝试生成可变参数扩展时尤其必要。

(如评论中所述,这也会阻止在解析字符串时生成适当的类型)。

举个例子,考虑一下 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 编写,其中 recursive consteval functions return [=20] 的一个实例=] -- 但这只有效,因为我们可以将值传递给 template-deduced 函数。更复杂的类型示例在 compile-time.

不会有这种奢侈

一般来说,像这样更复杂的type-generation需要一些级别的TMP,特别是如果类型对default-constructibility有限制,或者不能' t 本身是一个常量表达式。在这种情况下,这将需要开始属于一般 template-metaprogramming 实践的部分模板专业化。