模板元编程是否完全能够在 C++20 中被替代?
Is template metaprogramming fully able to be substituted in C++20?
虽然模板元编程的想法——尽可能在编译时计算一些东西——很棒,但我想知道当前的 C++20 特性是否允许我们通过使用 constexpr
、[=11 来完全避免 TMP =]、if constexpr
、concept
和其他 C++20 特性。这是真的?还是TMP提供的某些功能无法替代?
否,模板元编程不能完全被C++20语言实用程序取代;虽然大量可以。
constexpr
、consteval
等当然都有助于减轻传统上使用 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
}
此限制意味着更复杂的生成仍然需要传统的 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;
技术上 index_sequence
示例可以用 C++20 编写,其中 recursive consteval
functions return [=20] 的一个实例=] -- 但这只有效,因为我们可以将值传递给 template-deduced 函数。更复杂的类型示例在 compile-time.
不会有这种奢侈
一般来说,像这样更复杂的type-generation需要一些级别的TMP,特别是如果类型对default-constructibility有限制,或者不能' t 本身是一个常量表达式。在这种情况下,这将需要开始属于一般 template-metaprogramming 实践的部分模板专业化。
虽然模板元编程的想法——尽可能在编译时计算一些东西——很棒,但我想知道当前的 C++20 特性是否允许我们通过使用 constexpr
、[=11 来完全避免 TMP =]、if constexpr
、concept
和其他 C++20 特性。这是真的?还是TMP提供的某些功能无法替代?
否,模板元编程不能完全被C++20语言实用程序取代;虽然大量可以。
constexpr
、consteval
等当然都有助于减轻传统上使用 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
}
此限制意味着更复杂的生成仍然需要传统的 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;
技术上 index_sequence
示例可以用 C++20 编写,其中 recursive consteval
functions return [=20] 的一个实例=] -- 但这只有效,因为我们可以将值传递给 template-deduced 函数。更复杂的类型示例在 compile-time.
一般来说,像这样更复杂的type-generation需要一些级别的TMP,特别是如果类型对default-constructibility有限制,或者不能' t 本身是一个常量表达式。在这种情况下,这将需要开始属于一般 template-metaprogramming 实践的部分模板专业化。