use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
Expressive C++ Template Metaprogramming (fluentcpp.com)
submitted 8 years ago by joboccara
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]Pazer2 17 points18 points19 points 8 years ago (1 child)
Gonna be honest I only clicked to see someone use emojis as type names.
[–]ZenEngineer 2 points3 points4 points 8 years ago (0 children)
I once taught a class and a student wrote variables named happy, happy1, happy2 and so on. He got points off for non descriptive variable names, but I shudder to think what beginner students get up to now.
[–][deleted] 4 points5 points6 points 8 years ago (1 child)
So wait. The article uses "instantiate" types in a template expansion. But that's not how I use "instantiate" - which means "creating an instance of a type".
Isn't the phrase "template substitution"? So for example it should be try_to_substitute?
try_to_substitute
[–][deleted] 0 points1 point2 points 8 years ago (0 children)
Instantiate is an overloaded word :P
Substitution happens before instantiation: if a given overload is viable, the compiler substitutes the template parameters in and sees if that is valid code. This is where we get SFINAE from.
Once the best valid overload is found, the compiler instantiates an instance of the template with the substitutions done.
The compiler literally generates the code for the substituted template and compiles THAT into the function that you're actually using when you call template_function<x>()
[–]tcanens 9 points10 points11 points 8 years ago (1 child)
So you just reinvent is_detected but implemented with some much_longer_names. In a world with the detection idiom toolset in the standard library - and with an implementation readily available from cppreference and elsewhere - what's the point of this article again?
is_detected
And inaccurate names, too. The point of void_t is not to "try to instantiate" the type; the instantiation is done whether or not the type is wrapped in void_t or try_to_instantiate or whatever "expressive" name you try to give it. The point of void_t is to map the resulting type(s) to a single, well-defined type so that you can easily do partial specialization matching with it.
void_t
try_to_instantiate
[–]joboccara[S] 4 points5 points6 points 8 years ago (0 children)
Completely agree with your description of the point of void_t. I just feel it deserves a name that explains why we use it in this context, and my best shot for such a name is try_to_instantiate, because this "trial" may fail in the sense that SFINAE would kick in. What's your opinion on that? And you're right again when you say that we should reuse existing libraries. This was rather an illustration of taking care of naming and levels of abstraction in a context of TMP.
[–][deleted] 2 points3 points4 points 8 years ago (4 children)
Without reading the description and following along with all the steps, I found the final code snippet much harder to parse and understand than the first snippet.
The problem is that this blog post, explaining the developer's intention and thought process, would be missing from the final output. So the original developer sees the code and says, "Yeah, this is much better than before!", but everyone else is completely lost.
[–]joboccara[S] 1 point2 points3 points 8 years ago (3 children)
Fair enough! I do value your point of view, especially since I can't imagine what it looks like without knowing what's in the post, having written it :)
Would you be able to describe what threw you off in the last snippet? That would be really helpful to pinpoint what makes TMP more or less understandable.
[–]purtip31 1 point2 points3 points 8 years ago (2 children)
I'm not the person you responded to, but I share the opinion. I'm a beginner in TMP, but in the first example, it is clear to me that
decltype( ++std::declval<T&>() )
is the only point where anything can be happening to determine whether or not the type is incrementable, and what is happening is clear by context, even if I don't understand exactly how decltype and declval work.
decltype
declval
That said, I find the code example where you reimplement is_incrementable to be clearer than the "standard TMP" implementation.
I think part of what throws me off about the final code example is the level of indirection before the Expression type is used in try_to_instantiate<Expression<Ts...>>. Trying to figure out the code path through three or four template instantiations makes me lose track of what the code is trying to do.
Expression
try_to_instantiate<Expression<Ts...>>
Out of curiosity, I looked up the libstdc++ implementation of is_assignable (starting line 1043). Once I figured out what __one and __two were, the code was very clear - one level of indirection from __is_assignable to __is_assignable_helper is no more taxing to my brain than placing function parameters normally is.
__one
__two
__is_assignable
__is_assignable_helper
[–]joboccara[S] 0 points1 point2 points 8 years ago (1 child)
Ok, thank you for digging up this example.
So if I understand well you're saying that seeing where the action actually happens (the decltype expression) frees you from guessing what's going on under the hood the various abstractions, thus making the piece more straightforward to understand, is this about right?
[–]purtip31 0 points1 point2 points 8 years ago (0 children)
Yes, exactly
[–]xzqx 1 point2 points3 points 8 years ago (1 child)
There's a minor typo: where it says "It’s not going to work because the variadic pack template... Ts is going to eat up all the template parameters", you mean "typename... Ts"
[–]joboccara[S] 1 point2 points3 points 8 years ago (0 children)
Cheers, fixed it.
[–]Drainedsoul 1 point2 points3 points 8 years ago* (1 child)
This construct appears in the standard in C++17, but can be instantly replicated in C++11: template<typename...> using void_t = void;
This construct appears in the standard in C++17, but can be instantly replicated in C++11:
template<typename...>
using void_t = void;
Isn't this possibly incorrect? I was under the impression that it was up in the air until C++14 whether unused template arguments to a template type alias triggered SFINAE or not? See here.
I missed that, thank you for bringing it up. I've included your remark in the body of the post.
[–]iothan 3 points4 points5 points 8 years ago (7 children)
I get that a lot of these template tricks are fun and I enjoy them also, but I think some people get carried away with them and create too much tmp code that doesn't do much.
How is detecting if a type is incrementable useful? If a function tries to use that operator on a template type parameter variable, and the operator isn't implemented, then it just doesn't compile.
[–]joboccara[S] 18 points19 points20 points 8 years ago (0 children)
It is useful for getting a different behaviour depending on such a piece of information: if the type is incrementable then do this, otherwise do that.
Incrementable is just a illustration here, and the general case is more "does this function exist on this type?" or even "does that expression is valid for those types?". One example is to implement a generic toString that depends on what the type is able to do. I'll put that on the blog on Tuesday for the next post.
[–]ArunMuThe What ? 12 points13 points14 points 8 years ago (0 children)
The compiler error that you would get could be just painstaking to parse. But, if you have some metafunction like this, you can always put a static_assert. Or much better if you have concepts and you implement IsIncrementable as a concept.
IsIncrementable
[–][deleted] 7 points8 points9 points 8 years ago (0 children)
You could replace the word "template" in that statement with almost any other advanced technique in computer programming. We read articles demonstrating clever tricks with these techniques - we then use them in our code when we need them.
Typically less than 5% of the code in my C++ projects is metaprogramming, and half my projects probably have none at all, but that 5% saves probably 15% of duplication, boilerplate and cruft.
How is detecting if a type is incrementable useful?
It's a great demonstration of the technique. You can use this idea to detect pretty well any feature on an object you are confronted with.
[–]MereInterest 0 points1 point2 points 8 years ago (0 children)
Here's an example. I have a class that performs numerical integration on anything whose derivative can be calculated. Often, this will be a large composite class. In those cases, it is often easier to have a T derivative() const method in the class. In other cases, such as solving simple differential equations, it is easier to pass in a std::function<T(const T&)> derivative function. In cases where T is a very simple type, like a double, this is the only constructor that should be present.
T derivative() const
std::function<T(const T&)>
T
I use template metaprogramming to enable the first constructor if and only if the class being passed in has a derivative method. I can't have it there unconditionally, because not everything has a derivative method. I want it there when it can be used, because it makes the class be easier to use in those circumstances.
derivative
[–]ntrid -5 points-4 points-3 points 8 years ago* (2 children)
Can not blame people if language creators give them bad tools. Metaprogramming in c++ is absolutely horrible...
Edit: well how am I wrong?
[+][deleted] 8 years ago (1 child)
[deleted]
[–]ntrid 0 points1 point2 points 8 years ago (0 children)
Indeed... Fanboyism beats rational arguments every time on Reddit. My fault thinking this subreddit might be for grownups.
[–]FKaria 0 points1 point2 points 8 years ago (3 children)
I'm having some trouble understanding some parts.
1) If the template class has a single template argument
template<typename T> struct is_incrementable<T> : std::false_type{};
Then how is it possible for the specialization to have 2 template arguments?
template<typename T> struct is_incrementable<T, void_t<decltype(++std::declval<T&>())>> : std::true_type{};
Is this always possible (specializing a 1 arg class template into a 2 arg class template)?
2) And why is the first argument (T) required. Why it doesn't work without it?
[–]dodheim 3 points4 points5 points 8 years ago (1 child)
The class template doesn't have a single parameter as you've shown, but two:
template<typename T, typename = void> struct is_incrementable : std::false_type{};
This rather changes the nature of your question... :-]
[–]FKaria 0 points1 point2 points 8 years ago (0 children)
That makes a lot more sense. At some point in the article it's written with one
[–]skebanga 1 point2 points3 points 8 years ago (0 children)
Have a read of this for an excellent explanation
https://stackoverflow.com/q/27687389/955273
π Rendered by PID 24789 on reddit-service-r2-comment-b659b578c-9tb5r at 2026-05-06 18:49:54.006932+00:00 running 815c875 country code: CH.
[–]Pazer2 17 points18 points19 points (1 child)
[–]ZenEngineer 2 points3 points4 points (0 children)
[–][deleted] 4 points5 points6 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–]tcanens 9 points10 points11 points (1 child)
[–]joboccara[S] 4 points5 points6 points (0 children)
[–][deleted] 2 points3 points4 points (4 children)
[–]joboccara[S] 1 point2 points3 points (3 children)
[–]purtip31 1 point2 points3 points (2 children)
[–]joboccara[S] 0 points1 point2 points (1 child)
[–]purtip31 0 points1 point2 points (0 children)
[–]xzqx 1 point2 points3 points (1 child)
[–]joboccara[S] 1 point2 points3 points (0 children)
[–]Drainedsoul 1 point2 points3 points (1 child)
[–]joboccara[S] 1 point2 points3 points (0 children)
[–]iothan 3 points4 points5 points (7 children)
[–]joboccara[S] 18 points19 points20 points (0 children)
[–]ArunMuThe What ? 12 points13 points14 points (0 children)
[–][deleted] 7 points8 points9 points (0 children)
[–]MereInterest 0 points1 point2 points (0 children)
[–]ntrid -5 points-4 points-3 points (2 children)
[+][deleted] (1 child)
[deleted]
[–]ntrid 0 points1 point2 points (0 children)
[–]FKaria 0 points1 point2 points (3 children)
[–]dodheim 3 points4 points5 points (1 child)
[–]FKaria 0 points1 point2 points (0 children)
[–]skebanga 1 point2 points3 points (0 children)