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

I've got a really dumb question. My question is illustrated by the following code snippit.
template
T inline operator%(const T & lhs, const U & rhs) { if(0 == rhs) throw std::domain_error("Divide by zero"); if(boost::is_same ::value && boost::numeric::is_signed<U>::value ){ if(1 == rhs || -1 == rhs) // is this dropped? overflow("unsigned type can hold this result"); } return lhs % rhs; } I would like to think that the second if is always dropped from the compile for a particular pair of types since this can be evaluated at compile time.
I don't think the standard requires that it be dropped, but any decent compiler will do it if optimizations are enabled.
If I'm correct, I can replace some tedious template metaprogramming for some straightforward and transparent code inserted in a convenient code inserted in the most convenient place.
Andre Alex... gave a talk at "Going Native" proposing a "static if" for this case. But I don't see the necessity for for this since I would assume that the compiler just optimises away the "dead" code. I've compiled the above and it seems to do what I want but still I wonder.
Basically I see lots of applications of variations on this idea to get the benefits of tmp without the attendent pain.
Am I missing anything here?
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:
From:ramey@rrsd.com Date:Fri, 17 Feb 2012 12:40:12 -0800 I've got a really dumb question. My question is illustrated by the followingcode snippet.
template
T inline operator%(const T & lhs, const U & rhs) { if(0 == rhs) throw std::domain_error("Divide by zero"); if(boost::is_same ::value && boost::numeric::is_signed<U>::value ){ if(1 == rhs || -1 == rhs) // is this dropped? overflow("unsigned type can hold this result"); } return lhs % rhs;} I would like to think that the second if is alwaysdropped from the compile for a particular pairof types since this can be evaluated at compile time. If I'm correct, I can replace some tedioustemplate metaprogramming for some straightforwardand transparent code inserted in a convenient codeinserted in the most convenient place. Andre Alex... gave a talk at "Going Native" proposinga "static if" for this case. But I don't see the necessity forfor this since I would assume that the compilerjust optimises away the "dead" code. I've compiledthe above and it seems to do what I want butstill I wonder. Basically I see lots of applications of variationson this idea to get the benefits of tmp withoutthe attendent pain. Am I missing anything here? If you want to (partially) specialize on types, then use a class template that can act as a function object (i.e. has an operator ()). I was going to leave at that, but I see some other problems.
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:
I've got a really dumb question. My question is illustrated by the following code snippit.
template
T inline operator%(const T & lhs, const U & rhs) { if(0 == rhs) throw std::domain_error("Divide by zero"); if(boost::is_same ::value && boost::numeric::is_signed<U>::value ){ if(1 == rhs || -1 == rhs) // is this dropped? overflow("unsigned type can hold this result"); } return lhs % rhs; } I would like to think that the second if is always dropped from the compile for a particular pair of types since this can be evaluated at compile time.
If I'm correct, I can replace some tedious template metaprogramming for some straightforward and transparent code inserted in a convenient code inserted in the most convenient place.
Andre Alex... gave a talk at "Going Native" proposing a "static if" for this case. But I don't see the necessity for for this since I would assume that the compiler just optimises away the "dead" code. I've compiled the above and it seems to do what I want but still I wonder.
Basically I see lots of applications of variations on this idea to get the benefits of tmp without the attendent pain.
Am I missing anything here?
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

[...]
Andre Alex... gave a talk at "Going Native" proposing a "static if" for this case. But I don't see the necessity for for this since I would assume that the compiler just optimises away the "dead" code. I've compiled the above and it seems to do what I want but still I wonder.
Robert, I see Andrey's proposal aimed to replace the enable_if which is
On Fri, Feb 17, 2012 at 9:40 PM, Robert Ramey

Ovanes Markarian wrote:
On Fri, Feb 17, 2012 at 9:40 PM, Robert Ramey
wrote: [...]
Andre Alex... gave a talk at "Going Native" proposing a "static if" for this case. But I don't see the necessity for for this since I would assume that the compiler just optimises away the "dead" code. I've compiled the above and it seems to do what I want but still I wonder.
Robert, I see Andrey's proposal aimed to replace the enable_if which is based on SFINAE and greatly simplify the metaprogramming machinery. The code you present if fine and it might be optimized away by the compiler, but it might produce compilation errors, since all runtime branches of if-statement must be compilable without errors. SFINAE aimes to work around it, like we can enable some special treatment if the provided code "would compile" without errors.
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.
On the other hand using static if we might inspect the exposed type system of some type T. Let's say we would like to unify some different types using a traits class. Out traits class should expose value_type of the inspected type (say we have a boost::shared_ptr and std::vector as input). boost::shared_ptr contains a typedef of underlying type which is named element_type and std::vector names the underlying type value_type. Out traits type should homogenize these two types and provide a value_type member, which contains the underlying type of either shared_ptr or std::vector. It can be easily "calculated/specialized/inspected" with static if construct. How are you going to solve this problem with the runtime if without using enable_if , overloads and template specializations?
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
[...]
Hope that helps, Ovanes
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Sun, Feb 19, 2012 at 5:48 PM, Robert Ramey
** Ovanes Markarian wrote:
On Fri, Feb 17, 2012 at 9:40 PM, Robert Ramey
wrote: [...]
Andre Alex... gave a talk at "Going Native" proposing a "static if" for this case. But I don't see the necessity for for this since I would assume that the compiler just optimises away the "dead" code. I've compiled the above and it seems to do what I want but still I wonder.
Robert, I see Andrey's proposal aimed to replace the enable_if which is based on SFINAE and greatly simplify the metaprogramming machinery. The code you present if fine and it might be optimized away by the compiler, but it might produce compilation errors, since all runtime branches of if-statement must be compilable without errors. SFINAE aimes to work around it, like we can enable some special treatment if the provided code "would compile" without errors.
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.
[...] 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" [...]
On the other hand using static if we might inspect the exposed type system of some type T. Let's say we would like to unify some different types using a traits class. Out traits class should expose value_type of the inspected type (say we have a boost::shared_ptr and std::vector as input). boost::shared_ptr contains a typedef of underlying type which is named element_type and std::vector names the underlying type value_type. Out traits type should homogenize these two types and provide a value_type member, which contains the underlying type of either shared_ptr or std::vector. It can be easily "calculated/specialized/inspected" with static if construct. How are you going to solve this problem with the runtime if without using enable_if , overloads and template specializations?
Hmmm - a small code example might make this easier to understand
[...] 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
On Sun, Feb 19, 2012 at 5:48 PM, Robert Ramey
wrote: ** Ovanes Markarian wrote:
On Fri, Feb 17, 2012 at 9:40 PM, Robert Ramey
wrote: [...]
Andre Alex... gave a talk at "Going Native" proposing a "static if" for this case. But I don't see the necessity for for this since I would assume that the compiler just optimises away the "dead" code. I've compiled the above and it seems to do what I want but still I wonder.
Robert, I see Andrey's proposal aimed to replace the enable_if which is based on SFINAE and greatly simplify the metaprogramming machinery. The code you present if fine and it might be optimized away by the compiler, but it might produce compilation errors, since all runtime branches of if-statement must be compilable without errors. SFINAE aimes to work around it, like we can enable some special treatment if the provided code "would compile" without errors.
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.
[...] 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"
[...]
On the other hand using static if we might inspect the exposed type system of some type T. Let's say we would like to unify some different types using a traits class. Out traits class should expose value_type of the inspected type (say we have a boost::shared_ptr and std::vector as input). boost::shared_ptr contains a typedef of underlying type which is named element_type and std::vector names the underlying type value_type. Out traits type should homogenize these two types and provide a value_type member, which contains the underlying type of either shared_ptr or std::vector. It can be easily "calculated/specialized/inspected" with static if construct. How are you going to solve this problem with the runtime if without using enable_if , overloads and template specializations?
Hmmm - a small code example might make this easier to understand
[...] I am a little bit in hurry today, but will submit the example tomorrow.
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:
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"
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.
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 { ... }; } };
and my view would be that removing the "static" wouldn't change anything in the program - so why is it necessary.
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; } };
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

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 { ... }; } };
and my view would be that removing the "static" wouldn't change anything in the program - so why is it necessary.
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; } };
also in this example, removing the static wouldn't change the program in any way.
But the static_if is being used at class scope here - regular if statements cannot be used at class scope! Regards, Nate

Nathan Ridge wrote:
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 { ... }; } };
and my view would be that removing the "static" wouldn't change anything in the program - so why is it necessary.
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; } };
also in this example, removing the static wouldn't change the program in any way.
But the static_if is being used at class scope here - regular if statements cannot be used at class scope!
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
** whatever I said - what I mean is illustrated by the following
if(0){ ; // not checked by the compiler }
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:
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?
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:
On 27.02.2012 07:15, Nevin Liber wrote:
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?
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.
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

On 27.02.2012 15:53, Robert Ramey wrote:
Sebastian Redl wrote:
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 .... And if the condition happens not to be a constant expression, and both branches happen to compile with your particular instantiation of the template? I usually prefer that my intent is checked by the compiler.
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". I disagree. The syntax of C++ is weird in some places, but only a minor part of the "hardness" of C++. The "big" part is semantics: how name lookup works, especially in templates, how overload resolution and SFINAE work, those are the things that are hard to understand. The syntax isn't. The only hard part about the syntax is where syntax had to jump in for semantics, i.e. dependent name disambiguation with "typename" and "template". The part of static if that is hard to understand is what exactly it means for a branch to be discarded. What exactly is allowed in that branch? What happens to declarations in the branch, and under what circumstances am I allowed to use them outside of the branch? (By the way, the possibility of using declarations from inside on the outside, which is very useful, is a big reason not to use the normal if, where this would change semantics dramatically.) These are the things that aren't even clear yet (note that the current proposal leaves these things as open questions), and they are going to take a lot of standards lingo to specify and brainpower to understand. Putting a "static" in front of (or in my preferred syntax, after) the "if" is trivial. 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. Yes. That's exactly what this is about. How does making metaprogramming more readable make the language harder? OFF TOPIC
Seems many people are familiar with Andre's talk, I'm curious how many here attended "GoingNative" -in person -via web broadcast
Watched it via webcast. 2 days of conference are just not worth the expense and effort of traveling to the US. Sebastian

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.
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:
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.
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.
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.
Regards, Nate =

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.
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.
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)
You're right, of course. It should have been something like
is_same
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.
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

On 19 Feb 2012, at 23:28, Nathan Ridge wrote:
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.
Compilers are required to type-check such branches, and all compilers (well, everyone one I've ever used) does. Chris

Robert Ramey
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.
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