Is there any examples out there where template metaprogramming would be better to use than the new constexpr? From what I've understood, both constexpr and template metaprogramming have similar purposes, yet template metaprogramming is not obsolete. So there has to be some examples where template metaprogramming is preferred over constexpr. Any shared thoughts on this would be highly appreciated, thanks!
constexpr
provides true support for compile-time computing in the form of true C++ functions instead of functional-like template-based constructions (Metafunctions). So partially the answer is yes constexpr beats tmp on compile time computing, at least on its syntax for no fp initiated people used to C++. Note that I'm ignoring concerns about compiler performance etc.
On the other hand, tmp is still relevant, and actually the only way, to do type computing in C++. There are new approaches to improve the horrible tmp syntax, like what Boost.Hana does with template variables. But despite the syntax, is still a functional metalanguage separated from "normal" C++.
About type computing
From the two common tasks you may ask a C++ compiler for (Besides compiling), playing with the type system generating new types on demand depending on your requisites is something that constexpr cannot achieve, simply because that's not what constexpr is supposed/designed to do.
The fun part is that templates were not supposed to do compile-time computing neither. Even metaprogramming. They were designed as the C++ feature for generic programming. But you know the story, middle 90s "Whoaaa C++ templates are turing complete!", expression templates and blitz++ later, then Alexandrescu and his Loki. And now we have <type_traits>
and a serious proposal with a full fledged metaprogramming library inside.
Consider this example (Not mine, taken from this Eric Niebler "challenge"): Write an utility that gives you the common type between a set of types:
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>>>
{};
As you can see, this problem is about types. Something that constexpr is not supposed to do.
About the challenge, Eric asked both Louis Dionne (Boost.Hana author) and I to write common_type<Ts...>
using our libraries. Code above is Eric's implementation using his Meta library. Sincerely, I cannot beat Louis's fold + maybe monad solution :)
Literally any time you want to create a suite of related types that differ only in some of the types used therein. How would you implement std::vector<T>
with only constexpr
?
Templates and constexpr
perform different jobs, though in some cases an old template implementation may be swapped for a more concise version with constexpr
. These cases are hardly exhaustive, though.
constexpr
, not about templates' use in general. –
Psittacine std:vector<T>
is a template, but not an example of a template metaprogramming. –
Psittacine std::vector<T>
and have nothing to do with metaprogramming. –
Altdorf std::vector
, you are metaprogramming. You're not programming your C++ code: you're metaprogramming. The result is a type std::vector<int>
or a type std::vector<char>
etc that you then do regular programming with. –
Gratis constexpr
. Therefore, every other usage cannot be solved with constexpr
, which is the answer. –
Gratis std::vector<T>
code not as metaprogramming, but as generic progamming. When I go and use std::vector<int>
there is a metaprogramming part of instantiation - compiler does instantiation processing generic code. In this respect I agree with you - every time one uses template there is a metaprogramming part. Anyway, I think it was a good discussion. Thanks, guys. –
Psittacine © 2022 - 2024 — McMap. All rights reserved.
constexpr
? – Psittacine