模板元编程是否完全可以在 C++20 中替代?

K.R*_*ark 12 c++ templates template-meta-programming c++20

constexpr尽管模板元编程的想法(尽可能在编译时计算某些内容)非常棒,但我想知道当前的 C++20 功能是否允许我们通过使用、constevalif constexprconcept和其他 C++20 功能来完全避免 TMP 。这是真的?或者 TMP 提供的某些功能无法替代?

Hum*_*ler 9

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

constexprconsteval等等。所有这些肯定有助于减轻传统上使用 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
}
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

Live Example

从技术上讲,index_sequence示例可以用 C++20 编写,并使用返回实例的递归consteval函数index_sequence,但这只是因为我们可以将值传递给模板推导函数才有效。更复杂的类型示例在编译时不会有这种奢侈。

一般来说,像这样更复杂的类型生成将需要一定程度的 TMP,特别是如果类型对默认构造性有限制,或者本身不能是常量表达式。在这种情况下,这将需要部分模板专业化,这些专业化开始属于一般模板元编程实践。