Examples on template metaprogramming over constexpr?
Asked Answered
P

2

7

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!

Pizor answered 28/3, 2015 at 21:39 Comment(3)
How do you propose to achieve, say, compile-time polymorphism with constexpr?Psittacine
Related: https://mcmap.net/q/672674/-is-constexpr-really-needed-duplicate/560648Gratis
I think your wording of looking for examples makes people feel this is off-topic while what you are really trying to do is understand when tmp is required and constexpr is not an option.Spurious
A
10

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 :)

Altdorf answered 28/3, 2015 at 21:48 Comment(5)
Your first paragraph is basically the argument Sumant Tambe makes in the example for using constexpr instead in my answer here .. I am curious do you have an example that can fit in a typical SO answer of when tmp is required?Spurious
@ShafikYaghmour as far I'm concerned constexpr is more expensive from the compiler point of view that common template recursive instantiations. Actually the default max recursion limit of constexpr is much more less than the tmp one. On the other hand, C++14 constexpr allows loops. So no rec is required almost never.Altdorf
@ShafikYaghmour so maybe the answer is: Use constexpr for compile-time computing. The point is that almost nobody does pure compile-time computing, but play with types instead. And constexpr has nothing to do there.Altdorf
Could you elaborate on type computing in terms of this question? What it means in the discussion of whether to prefer template metaprogramming over constexpr? This is a really great answer though, thanks!Pizor
@Foreveranoob sure, give me a minuteAltdorf
G
-1

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.

Gratis answered 28/3, 2015 at 21:52 Comment(15)
I think OP talks about template metaprogramming and constexpr, not about templates' use in general.Psittacine
@Petr: The use of templates is template metaprogramming.Gratis
Correct me if I'm wrong, but I thought template metaprogramming is about "performing computations" during compile time. In my understanding it's only a subset of template usage. I mean, std:vector<T> is a template, but not an example of a template metaprogramming.Psittacine
For almost every C++ programmer templates are std::vector<T> and have nothing to do with metaprogramming.Altdorf
@Petr: "Template metaprogramming (TMP) is a metaprogramming technique in which templates are used by a compiler to generate temporary source code, which is merged by the compiler with the rest of the source code and then compiled. The output of these templates include compile-time constants, data structures, and complete functions." When you define a template 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
Executing value computations with templates is just one branch of template metaprogramming, and it's the only branch that can be solved instead with constexpr. Therefore, every other usage cannot be solved with constexpr, which is the answer.Gratis
@Manu343726: Not really relevant how many C++ programmers get it wrong!Gratis
Even if the template mechanism generates code under the hood and that's a type of metaprogramming, you know perfectly what the community knows as tmp: There are simple templates as glorified Java generics (That are the C++ templates for 90% of C++ programmers), and there are complex ones where you compute types, generate new classes, do complex specializations, traits, etc (TMP, templates for C++ mads).Altdorf
@Manu343726: I am honestly lost as to what you're talking about. TMP is what I quoted the definition of above. If you have some C++ programmer friends who get the definition wrong then that is their problem! Your answer is great though and I'd already upvoted it. So this is pretty pointless.Gratis
What I mean is that the OP asked about TMP, asked about the common definition of TMP. Maybe you are right, not the correct TMP def, but still what people understands as TMP. Keep in mind that people will read the topic in the future and talking about TMP == templates may mislead them. Is that incorrect and we should talk about tmp properly? That's a completely different topic. An interesting topic which deserves a question here I thinkAltdorf
Maybe I'm wrong, but I understand 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
There are no generics in C++. Perhaps you're thinking of Java!Gratis
In C++ generic programming is done with templates.Psittacine
@LightnessRacesinOrbit It seems you have very unconventional definitions. C++ templates are exactly the tool for generic programing. STL in C++ is an example of generic programming, and was designed and implemented by Stepanov who is all about generic programming (wrote a library in Ada first, then moved to C++ and made STL; tried to convince Stroustrup to introduce generics in C++ initially)...Psittacine
I'm sorry you feel that way.Gratis

© 2022 - 2024 — McMap. All rights reserved.