constexpr 上的模板元编程示例?
Examples on template metaprogramming over constexpr?
是否有任何示例表明模板元编程比新的 constexpr 更好用?据我了解,constexpr 和模板元编程都有相似的目的,但模板元编程并没有过时。所以必须有一些例子,其中模板元编程比 constexpr 更受欢迎。任何对此的共同想法将不胜感激,谢谢!
constexpr
以真正的 C++ 函数形式提供对编译时计算的真正支持,而不是基于模板的函数式构造(元函数)。所以部分答案是 是 constexpr 在编译时计算 上胜过 tmp ,至少在它的语法上对于没有使用 fp 的人来说是习惯 C++ 的。请注意,我忽略了对编译器性能等的担忧。
另一方面,tmp 在 C++ 中进行类型计算仍然是相关的,而且实际上是唯一的方法。有一些新的方法可以改进可怕的 tmp 语法,比如 Boost.Hana 对模板变量所做的。但是尽管有语法,它仍然是一种与 "normal" C++ 分离的功能元语言。
关于类型计算
从您可能要求 C++ 编译器完成的两个常见任务(除了编译),使用类型系统根据您的要求按需生成新类型是 constexpr 无法实现的,因为这不是 constexpr 的目的supposed/designed 去做。
有趣的是模板也不应该进行编译时计算。甚至是元编程。它们被设计为通用编程的 C++ 特性。但你知道这个故事,90 年代中期 "Whoaaa C++ templates are turing complete!",后来是表达式模板和 blitz++,然后是 Alexandrescu 和他的 Loki。现在我们有了 <type_traits>
和一个严肃的提议 with a full fledged metaprogramming library inside.
考虑这个例子(不是我的,取自 Eric Niebler "challenge"):编写一个实用程序,为您提供一组类型之间的通用类型:
namespace m = ranges::meta;
namespace ml = ranges::meta::lazy;
template<typename T, typename U>
using builtin_common_t =
decltype(true? std::declval<T>() : std::declval<U>());
template<typename T, typename U>
using lazy_builtin_common_t =
m::defer<builtin_common_t, T, U>;
template<typename...Ts>
struct common_type
{};
template<typename ...Ts>
using common_type_t = m::eval<common_type<Ts...>>;
template<typename T>
struct common_type<T>
: std::decay<T>
{};
template<typename T, typename U>
struct common_type<T, U>
: m::if_c<
( std::is_same<decay_t<T>, T>::value &&
std::is_same<decay_t<U>, U>::value ),
ml::let<lazy_builtin_common_t<T, U>>,
common_type<decay_t<T>, decay_t<U>>>
{};
template<typename T, typename U, typename... Vs>
struct common_type<T, U, Vs...>
: ml::let<ml::fold<m::list<U, Vs...>, T, m::quote<common_type_t>>>
{};
如你所见,这个问题是关于类型的。 constexpr 不应该做的事情。
关于挑战,Eric 要求 Louis Dionne(Boost.Hana 作者)和我使用我们的库编写 common_type<Ts...>
。上面的代码是 Eric 使用他的 Meta 库实现的。真诚的,我无法击败 Louis 的 fold + 也许是 monad 解决方案:)
从字面上看,任何时候您想要创建一组相关类型,这些类型仅在其中使用的某些类型上有所不同。您将如何仅使用 constexpr
来实现 std::vector<T>
?
模板和 constexpr
执行 不同的工作 ,尽管 in some cases an old template implementation may be swapped for a more concise version with constexpr
。不过,这些案例并不详尽。
是否有任何示例表明模板元编程比新的 constexpr 更好用?据我了解,constexpr 和模板元编程都有相似的目的,但模板元编程并没有过时。所以必须有一些例子,其中模板元编程比 constexpr 更受欢迎。任何对此的共同想法将不胜感激,谢谢!
constexpr
以真正的 C++ 函数形式提供对编译时计算的真正支持,而不是基于模板的函数式构造(元函数)。所以部分答案是 是 constexpr 在编译时计算 上胜过 tmp ,至少在它的语法上对于没有使用 fp 的人来说是习惯 C++ 的。请注意,我忽略了对编译器性能等的担忧。
另一方面,tmp 在 C++ 中进行类型计算仍然是相关的,而且实际上是唯一的方法。有一些新的方法可以改进可怕的 tmp 语法,比如 Boost.Hana 对模板变量所做的。但是尽管有语法,它仍然是一种与 "normal" C++ 分离的功能元语言。
关于类型计算
从您可能要求 C++ 编译器完成的两个常见任务(除了编译),使用类型系统根据您的要求按需生成新类型是 constexpr 无法实现的,因为这不是 constexpr 的目的supposed/designed 去做。
有趣的是模板也不应该进行编译时计算。甚至是元编程。它们被设计为通用编程的 C++ 特性。但你知道这个故事,90 年代中期 "Whoaaa C++ templates are turing complete!",后来是表达式模板和 blitz++,然后是 Alexandrescu 和他的 Loki。现在我们有了 <type_traits>
和一个严肃的提议 with a full fledged metaprogramming library inside.
考虑这个例子(不是我的,取自 Eric Niebler "challenge"):编写一个实用程序,为您提供一组类型之间的通用类型:
namespace m = ranges::meta;
namespace ml = ranges::meta::lazy;
template<typename T, typename U>
using builtin_common_t =
decltype(true? std::declval<T>() : std::declval<U>());
template<typename T, typename U>
using lazy_builtin_common_t =
m::defer<builtin_common_t, T, U>;
template<typename...Ts>
struct common_type
{};
template<typename ...Ts>
using common_type_t = m::eval<common_type<Ts...>>;
template<typename T>
struct common_type<T>
: std::decay<T>
{};
template<typename T, typename U>
struct common_type<T, U>
: m::if_c<
( std::is_same<decay_t<T>, T>::value &&
std::is_same<decay_t<U>, U>::value ),
ml::let<lazy_builtin_common_t<T, U>>,
common_type<decay_t<T>, decay_t<U>>>
{};
template<typename T, typename U, typename... Vs>
struct common_type<T, U, Vs...>
: ml::let<ml::fold<m::list<U, Vs...>, T, m::quote<common_type_t>>>
{};
如你所见,这个问题是关于类型的。 constexpr 不应该做的事情。
关于挑战,Eric 要求 Louis Dionne(Boost.Hana 作者)和我使用我们的库编写 common_type<Ts...>
。上面的代码是 Eric 使用他的 Meta 库实现的。真诚的,我无法击败 Louis 的 fold + 也许是 monad 解决方案:)
从字面上看,任何时候您想要创建一组相关类型,这些类型仅在其中使用的某些类型上有所不同。您将如何仅使用 constexpr
来实现 std::vector<T>
?
模板和 constexpr
执行 不同的工作 ,尽管 in some cases an old template implementation may be swapped for a more concise version with constexpr
。不过,这些案例并不详尽。