5 ms·
What are unevaluated operands in C++?
- voldacar 7y agoPoor man's lazy evaluation. I'm sure they'll try to shoehorn monads in somehow with C++23
- afranchuk 7y agoI'm not sure what lazy evaluation had to do with it... but it's something that will be much easier when concepts are in the language with C++20.
- kadoban 7y agoIt's not lazy evaluation at all. Lazy evaluation is a runtime thing, where you delay evaluating an expression until you actually need to. This concept is operators that will never evaluate the expressions they operate on. sizeof is the oldschool obvious one, sizeof(foo()) never runs the function foo. It's just a way of querying the static properties of an expression, asking specific things about its type in a way. They're not new things in C++. sizeof has been around since the beginning.
- gumby 7y agoI thought this would be about the arm of a conditional not taken but as soon as he listed the operators it all became clear.
- saagarjha 7y agoA fun (or maybe horrifying) bit of trivia is that sizeof in C can end up evaluating its operand in certain cases; namely, when you use it on a VLA: https://godbolt.org/z/-UX2KQ https://godbolt.org/z/-UX2KQ
- haberman 7y agoThis seems like a potential solution to the problem of how to #define MY_ASSERT(x) in release mode such that it fails to compile if "x" is not a valid expression. Previous I have used this idiom: #define MY_ASSERT(expr) do {} while (false && (expr)) Another possible alternative might be: #define MY_ASSERT(expr) sizeof(expr)
- jcranmer 7y ago> #define MY_ASSERT(expr) sizeof(expr) sizeof accepts a type or an expression as its input, so it would compile successfully if expr were a type but not a valid expression (say, int).
- edflsafoiewq 7y agoYou could do sizeof((expr)?1:2) instead, which would also force expr to be contextually convertible to a bool.
- pandaman 7y agosizeof((expr)) would suffice to filter out types.
- leni536 7y agoNote that lambda expressions are not allowed in an unevaluated context. What about this? #define MY_ASSERT(expr) do {} while (false && ((expr), false)) This doesn't require expr to be convertible to bool.
- DerekL 7y agoActually, the argument of MY_ASSERT should always be convertible to bool, even in release mode.
- DerekL 7y agoWhy not just #define MY_ASSERT(expr) ((void)(false && (expr))) The problem the do-while idiom is that the macro result is not an expression, so it can’t be used in certain cases.
- leni536 7y agoThis kind of tag dispatch to disambiguate is really clever. I never thought of disambiguating based on the conversion of the tag. Edit: I have probably seen it in concepts lite though, I just forgot about it.
- dgellow 7y agoIf you don’t know what SFINAE is (the article uses the acronym a lot but doesn’t define it): > Substitution failure is not an error (SFINAE) refers to a situation in C++ where an invalid substitution of template parameters is not in itself an error. https://en.m.wikipedia.org/wiki/Substitution_failure_is_not_an_error https://en.m.wikipedia.org/wiki/Substitution_failure_is_not_...
- kccqzy 7y agoThis is a intermediate-level technique that's quite commonly used. Take a look at <type_traits> to find out what you can do with it! Specifically you can use std::enable_if in a return type or template parameter to conditionally enable an overload.
- quietbritishjim 7y agoSmall typo near start: > Up to C++17, there are four operators the operands of which are unevaluated: typeof, sizeof, decltype, and noexcept. "typeof" should be "typeid". This confused me a bit as I thought the article was going to talk about a nonstandard predecessor to decltype. The article was interesting, but its contents didn't really match it's title. It's not about unevaluated operands in general but just their use in SFINAE specifically. For example, sizeof is dismissed as not much use for SFINAE, which is true but it certainly has a lot of other uses! And if you read this article having not seen decltype before, I think you'd get the wrong impression about its range of uses.
- gpderetta 7y agoconfusingly typeid can evaluate its expression parameter, if the expression type is polymorphic as the correct type info would be a runtime property (in fact I thought that typeid would always evaluate its parameters, but apparently that's not the case).
- nmeofthestate 7y agoI'm a c++ programmer but honestly hate the language more and more with every year, because it's so complex. Can somebody explain the first code sample to me?
- dkersten 7y agoI agree. I really liked C++11, it seemed to be a big improvement to the language, but ever since then, its just been getting more and more complex to the point where I no longer feel like I can understand the language at all anymore.