
I've got a really dumb question. My question is illustrated by the
following
code snippit.
template

I don't think the standard requires that it be dropped, but any decent compiler will do it if optimizations are enabled.
For a runtime "if", the compiler will still type-check the body of the if statement even if it ends up being optimized away. "static if" is useful in cases where you want to write code in the body that is valid for the types for which the "static if" passes, but not necessarily valid for other types. Regards, Nate

From: ramey@rrsd.comDate: Fri, 17 Feb 2012 12:40:12 -0800
I've got a really dumb question. My question is illustrated by the followingcode snippet. template

Daryle Walker wrote:
Hmmm - this doesn't answer my question. My question is: is there any reason that my example is a bad idea. It works as I expect and is the equivalent of the TMP solution (assuming that the C++ compiler eliminates dead code - which is presumed to be widely implemented though not required by the standard.) To me it yields all the benefits detailed in Andrei's proposal for "static if". The only problem I have with it is that it depends upon widely implemented behavior which is not required by the standard. questions: a) is this a problem? b) are there any other problems which I haven't noticed? Robert Ramey

On 17 Feb 2012, at 20:40, Robert Ramey wrote:
No, you are missing nothing at all. The normal reason you have to use TMP is because inside of the if won't compile for one set of types. You can be sure that this code will be removed. gcc will remove it even without optimisation turned on. Switching to TMP will remove the code, but a compiler so terrible that it doesn't do dead code elimination probably wouldn't also inline the TMP functions, leading to more overhead anyway. If you ever want to see what g++ gets up to in a (reasonably) readable fashion, add '-fdump-tree-all', and read the output with the highest number, which isn't statistics. Note that this isn't all the optimisation gcc does, but covers much of the high-level optimisation. Chris

On Fri, Feb 17, 2012 at 9:40 PM, Robert Ramey

Ovanes Markarian wrote:
Basically this example is the first slide in Andrei's talk. The purpose was to introduce a use case for the need for "static if". To my mind it failed in its purpose since a "normal if" already does that. It's even worse - Andrei ruminated on the question as to what should be done with the "dead" branch. i.e. should it be skipped entirely or actually compiled - he left that question open. It seemed to me that for this case, the whole question could be addressed by adding language to the standard that a compiler should elminate code for which it can be determined at compile time will never be run. The reason I brought this up is that since he's well known as a smart guy (and one hell of an entertainer), I thought I must be missing something - but it looks like I'm not at least in this example. The other use case he used (whose details I now can't remember) could easily have been addressed with static_assert which is already in the language. So my original question has been answered - that is I can just use compile time integral constants and know that any dead code will just not appear. I can do this right now and know that I won't have any future surprises. So far so good. Now you've raised an entirely new and interesting question. Assuming I'm correct and that Andrei's use cases don't make the case for static if - Is there a real case for static if.
Hmmm - a small code example might make this easier to understand But looking aournd I found http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3322.pdf which has the examples. This example is basically the same as mine above. To me it fails to make the case that static if is required and couldn't be just replaced with a normal if along with the certainty that the compiler will eliminate dead code.
IMO static if is aimed to simplify lot's of code, make it readable and understandable, this is what it is about.
I totally get that. The question is why is it necessary when one can just use normal if and count on dead code elimination. Robert Ramey

On Sun, Feb 19, 2012 at 5:48 PM, Robert Ramey
[...] Robert, somehow I do not get your proposal. How do you consider an if-branch, which is not going to compile, i.e. compilation error. Do you propose, to ignore that branch and just state: "OK, if there is a compilation error, that must be eliminated without any errors to the end-user". I don't think this can work. Therefore there should be a special language construct, which states: "if there is a compilation error, than it is safe to be ignored during the compilation" [...]
[...] I am a little bit in hurry today, but will submit the example tomorrow. With Kind Regards, Ovanes

Robert,
I just write the answer which I promised earlier...
On Sun, Feb 19, 2012 at 7:41 PM, Ovanes Markarian
Sorry it took me a bit longer, but here are my ideas.... Code from Slide 12 of Andrei's presentation at Going Native 2012: template<class T> struct container { ... static if(debug_mode<T>::value) { class const_iterator { ... }; static if(std::is_const<T>::value) { typedef const_iterator iterator; } else { class iterator { ... }; } } else { class const_iterator { ... }; clas iterator { ... }; } }; static if allows to expose the static interface. Now my example was trying to introduce the following: Let's assume that shared_ptr<T> only has the element_type type member and e.g. auto_ptr<T> has the value_type type member. What we need is to have a machinery to unify these two type templates and retrieve the type of the pointer from them. This can't be done with runtime if, but as example shows with static if. Not sure if C++11 has something similar as MPL's analogon of BOOST_MPL_HAS_XXX_TRAIT_DEF(name) from: http://www.boost.org/doc/libs/1_42_0/libs/mpl/doc/refmanual/has-xxx-trait-de..., therefore I will use it in my example: BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type); template<class PointerWrapper> struct grab_pointer_type { static if(has_element_type<PointerWrapper>::value) { typedef typename PointerWrapper::element_type pointer_type; } else { typedef typename PointerWrapper::value_type pointer_type; } }; Hope that helps, Ovanes

Ovanes Markarian wrote:
whatever I said - what I mean is illustrated by the following if(0){ ; // not checked by the compiler } and of course the same would occur for any expression which resulted in a 0 or false at compile time.
and my view would be that removing the "static" wouldn't change anything in the program - so why is it necessary.
also in this example, removing the static wouldn't change the program in any way. The only problem comes about when the dead code won't compile. Just skipping the dead code would fix this problem. btw - andrei left it as an open question whether the compiler should try to parse the dead code or just throw it away. Robert Ramey

Nathan Ridge wrote:
lol - I completely overlooked the fact this isn't a function - which was my original question. As I remember, andrei's other example could have been better handled with a static_assert - but I may be mis-remembering. the above case would be handled adequetly today with TMP which admitadly is an unwieldy syntax. Robert Ramey
Regards, Nate

On 26 February 2012 23:10, Robert Ramey
When you specify what you mean by "not checked by the compiler", then we'll talk. :-) Until you do, it is trivial to poke holes in it. For instance: if (0) { Fire Fire Fire! (note: this line is NOT a C++ comment) if (ShouldTheIf0OnlyGoToTheFirstEndBraceItFinds()) { } LaunchTheMissiles(); if (0) { } Did you really mean to launch the missiles? -- Nevin ":-)" Liber mailto:nevin@eviloverlord.com (847) 691-1404

On 27.02.2012 07:15, Nevin Liber wrote:
That's not Robert's obligation to answer, since the original static if proposal leaves the details of this question open as well. (Note, though, that Andrei said that at the very least, the parser would have to ensure that the tokens are brace-balanced in the dead branch. There is no sane way to parse the example you've just given.) Robert's suggestion is just that "static if" can be replaced by "if" if the compiler is simply required to act as if the "if" was a "static if" if the condition is a constant expression. I think this is feasible. I also think it obscures intent, which is why I'm against it. Sebastian

Sebastian Redl wrote:
Thanks for expressing this more clearly than I have.
I think this is feasible. I also think it obscures intent, which is why I'm against it.
It's easy to express intent without adding anything to the language /* static */ if .... I'm concerned about adding stuff to the language syntax which doesn't really add any functionality. This makes the language "bigger" to understand without making the functionality "bigger". C++ is already way to hard to understand and I don't think proposals like this don't reallly help. What this is really about is how to incorporate TMP functionality into the language in a way which doesn't make the language unreadable. OFF TOPIC Seems many people are familiar with Andre's talk, I'm curious how many here attended "GoingNative" -in person -via web broadcast Robert Ramey
Sebastian

Yes. Here's an example: template <typename Iterator> void advance(Iterator it, size_t n) { static_if(iterator_category<it>::type == random_access_category_tag) { it += n; } else { for (size_t i = 0; i < n; ++i) ++it; } } Were one to use a runtime if instead, and instantiate the function with an iterator that is not random access, one would get a compiler error of the form 'no match for operator+=(Iterator, size_t)'. The idea is that with a runtime if, the compiler type-checks the unused branch even if it ends up eliminating it in later on in the optimization phase. Regards, Nate

Nathan Ridge wrote:
Well, this seems like a better example, but ... the following wouldn't compile anyway as if can't compare types. if(iterator_category<it>::type == random_access_category_tag) I'm not sure as to whether the proposal actually expands if to compare types. Anyway, one could right right now: if(is_random_access_iterator<Iterator>::value){ it += n; } else{ for(size_ti = 0; i < n; ++i){ ++it; } IF the compiler skipped the "false" branch. I would guess this behavior is undefined (but maybe not). So maybe everything would be just fine if behavior in this case were defined to skip branches known to be false at compile time. Of course this presumes that there iterator traits implemented as integral boolean compile time constants. But this is no more burdensome comparing tag types Actually, I did look at the proposal and it includes a bunch of new syntax not explained in Andrei's talk. (that doesn't really convince me either - but of course that's off topic). Anyway, I did get what i wanted from my question - I can just use if(... dependent on a template paramter) whereever it makes syntactical sense and get what I expect to get. Thanks to all who participated in this thread.

You're right, of course. It should have been something like
is_same
I'm not sure whether compilers are required by the standard to type-check branches known not to be taken at compile time, but in practice I think they do because type-checking is done at an earlier stage of compilation than optimizations like constant propagation. Regards, Nate

Robert Ramey
It's not just this. In case of normal if, both branches are being compiled (even if one branch will be discarded later), but in case of static if (or any other existing replacement like enable_if, overloading by true_type/false_type etc) only one branch is is compiled. So of course you can't use normal if when the branches can't be compiled at the same time (this is what you call "syntactical sense"), but even when they can be compiled together it may be not the best way to go. The reason is: this stuff usually appears in template code, so it usually calls other templates in turn, and the number of instantiations needed to compile both branches can be huge, and you'd probably wanted to avoid this. It's basically the same reasoning as with checking template arguments: it's better to check all of them first and only if all args are ok call another function that will do the work, otherwise call an empty function that will just report the error (and select between them statically via true_type/false_type overload). If you don't do this and just write one big function that has all that checks in the beginning, even in the case of check failure the compiler will continue to compile the rest of the body, instantiating more and more templates and printing more and more errors. So the real answer is: you need static if (or any other replacement) when you don't want the compiler to try to compile the unneeded branch (whether it will give an error if compiled or it's just too heavy to compile). Thanks, Maxim
participants (8)
-
Christopher Jefferson
-
Daryle Walker
-
Maxim Yanchenko
-
Nathan Ridge
-
Nevin Liber
-
Ovanes Markarian
-
Robert Ramey
-
Sebastian Redl