| ||||
| Comment on GotW #92 Solution: Auto Variables, Part 1 by Ralph Tandetzky
Maybe you should mention that volatile is also stripped from the right hand side type for completeness. This highlights the symmetry of const and volatile. Are there any other things that can be stripped? In the second section you say “such as top-level const-ness and reference-ness”. Instead you could say “which are top-level const-ness, volatile-ness and reference-ness”. Just a thought. Read More »Comment on GotW #92 Solution: Auto Variables, Part 1 by Leo
@monamimani auto h = cir; is equivalent to auto h = val; In the case of f ip is not a different name for val. It’s a pointer to a location in memory, it contains an address. auto f = ip; assigns to f the address contained in ip, not the integer contained in val. Read More »Comment on GotW #93: Auto Variables, Part 2 by mttpd
// Note: posting _once_ again (I *really* wish there was an “edit” option at this point), feel free to remove my previous comments (and this note), was hoping to avoid the hassle with URL formatting, obviously didn’t work; also fixed a few typos and a bug; sorry for any inconvenience this might have caused :-) 1.(a) We can generalize the code from using `int` to other value_types stored in std::vector. // On a side note: I usually prefer to use `it` for iterators and `i` for indexes for easy disambiguation. However, since we’re relying on the RandomAccessIterator concept when we do `it += 2`, we can’t generalize beyond the types which model it (as long as we’re talking about the Standard), `std::vector`, `std::array`. and `std::deque` (an old C-style array would work, too). Overall, it’s worth remembering Scott Meyers’ advice from “Effective STL”: “Item 2: Beware the illusion of container-independent code.” However, given that there are multiple types modeling RandomAccessContainer for which `traverse` makes sense, there’s a case for making our `traverse` a bit more generic: template <typename RandomAccessContainer> void traverser( const RandomAccessContainer & v ) { using std::begin; using std::end; for( auto it = begin(v); it != end(v); it += 2 ) First, the error part (easily tested for 1-sized vector): since we’re traversing with non-unit stride, we have a potential out of bounds error here (stepping too far). First, we have to change the test condition (`it` relies on being `RandomAccessIterator` for this type of traversal anyway, so that’s fine; see the aforementioned “Item 2″): for( auto it = begin(v); it < end(v); it += 2 ) That’s not the end of it — advancing an iterator past the end is actually undefined behavior. Now, let me explain the using declarations `using std::begin` and `using std::end`. Given all these issues, I’d actually *strongly* consider using indexes here — note that we won’t lose any genericity, since we’re relying on having a `RandomAccessContainer` anyway — again, to repeat Scott Meyers’ advice from “Effective STL”: “Item 2: Beware the illusion of container-independent code.” Hence, after further consideration, I think I might possibly go against the grain here and suggest the following instead (together with including `cstddef`): for( std::size_t i = 0; i < 0; i += 2 ) If one insists on using iterators here, I think we have to go Boost and use `boost::strided_range` / `boost::adaptors::strided`. // using C++14 polymorphic lambda #include <boost/range/adaptor/strided.hpp> #include <boost/range/algorithm/for_each.hpp> template <typename RandomAccessContainer> void traverser( const RandomAccessContainer & input ) { using namespace boost::adaptors; boost::for_each( input | strided(2), [](auto value) { /* std::cout << value; */ }); } To avoid unreadeable compiler diagnostics if our input cointainer’s type doesn’t model `RandomAccessContainer` concept: 1.(b) vector<int> v1{5}; See also “Intuitive interface — Part I” on “Andrzej’s C++ blog” :-) 1.(c) auto w { get_gadget() }; On a side note, perhaps it’s also a good idea to keep the standard convention of naming the factories “make”: auto w { make_gadget() }; 1.(d) `std::function` implies type-erasure and performance drop due to run-time operations, which is probably not what we want. auto get_size = [](vector<int> x) { return x.size(); }; It’s worth noting that beyond being unspecified, type names are also unique, so `decltype` wouldn’t work either. On a side note, note that (for similar reasons) we’d also prefer to use `auto` if our right-hand side object was a forwarding call wrapper returned by `std::bind` — so, it’s not just needed for lambdas :-) 2.(a) Can’t really see an application for `auto` here, I think `auto w { widget() }` might be going somewhat overboard (it’s not even shorter to type, don’t see any clarity gain). 2.(b) Problem #1: using an `int` for a variable storing the size is a horrid crime against humanity! :D I would’ve used `std::size_t` from `cstddef`, but I can see a case where `auto` could also work here. // WRONG: using `int` for size is bad and you should feel bad for (int iWRONG = 0; iWRONG < v.size(); i += 2) now, let’s say we’d try to use `auto`: // STILL WRONG: using `int` for size is bad and you should feel bad for (auto iWRONG = 0; iWRONG < v.size(); i += 2) The comment still stands, since the type of literal `0` is `int`! for (std::size_t i = 0; i < v.size(); i += 2) 2.(c) Hard-coding `int` ignores the integral promotion and the “usual arithmetic conversions” (UAC) rules. auto total = x + y; 2.(d) This could get tricky, since the UAC could imply a promotion-to-unsigned, making the later predicate `diff < 0` trivially always-false. To make this even more fun, it's actually implementation defined whether, say, `long int` or `unsigned int` "wins" in the promotion battle :-) See Stephan T. Lavavej – Core C++, 7, Usual Arithmetic Conversions and Template Metaprogramming: See also: This won't do either: if (x < y) { /*...*/ } Compliant Solution from the CERT's INT02-CPP (which also explains how the above code is not robust to the integral promotion and UAC rules): Given the C++11's type traits, we can modify the above solution so that the argument to be given to `static_cast` is obtained using `std::make_signed`: 2.(e) Well, here the intent is unclear, since the truncation from `double` (implied by the `42,0` literal) to `int` could possibly have been desired — in this case, however, an explicit `static_cast` would be in order (for clarity). If the truncation is undesired, we'd be better off with the following: auto i = f(1,2,3) * 42.0;Read More » Comment on GotW #93: Auto Variables, Part 2 by mttpd
Come to think of it, I’d also replace the lambda in 1.(a) with the following (still C++14): [](const auto & value) { /* std::cout << value; */ } or, if the C++14 polymorphic lambdas support universal references (which they hopefully do), simply: [](auto && value) { /* std::cout << value; */ } (for automatic const-correctness with less typing; and to handle a certain nasty proxy case ;]). Read More »Comment on GotW #93: Auto Variables, Part 2 by mttpd
Sigh… one more typo :-) This time, in the code in “1.(a)”, which instead of for( std::size_t i = 0; i < 0; i += 2 ) should say for( std::size_t i = 0; i < v.size(); i += 2 ) Giving how easy it is to make typos in this context, I’m becoming more and more inclined toward recommending the Boost.Range solution here :-) Let me use this opportunity to make one more note on the genericity — the Boost.Range solution in fact only requires a type that is a model of Single Pass Range. This corresponds to an iterator type being a model of Single Pass Iterator (which has even less requirements than a Forward Traversal iterator, let alone a Random Access Iterator). One could ask then, isn’t requiring a RandomAccessContainer an over-specification? If we go down the road of increased genericity, we’d have to use a `SinglePassRange` concept instead (or `SinglePassContainer` / `SinglePassIterator` where applicable) and carefully document the performance impact of having types modeling a different levels of refinement of this concept. Read More »Comment on GotW #93: Auto Variables, Part 2 by David Thornley
1. In // (c) gadget get_gadget(); // ... widget w = get_gadget(); changing the variable declaration to auto w = get_gadget(); could be less safe. In the first case, we get a compile error unless we have an automatic conversion from gadget to widget. If we have one, there is no error, but presumably then w is a functioning widget. If we write w.Foo(), we know we’re using widget::Foo(). Either there’s a compiler error or there are no surprises. In the second case, the type of w is gadget, but we don’t realize that. We’re presumably assuming the type of w is widget. As long as we don’t call any function that doesn’t have a counterpart of the same name in gadget, we’re not going to get a compile error, and we’re going to be mistaken in what we’re calling. If we write w.Foo(), we’re calling gadget::Foo(), which may do something unexpected if we’re unlucky. Read More »Comment on GotW #93: Auto Variables, Part 2 by mttpd
Again, assuming C++14 with polymorphic lambdas supporting universal references, let’s change the code in 1.(d) to: auto get_size = [](auto && x) { return x.size(); }; (for the reasons see my previous comment). Read More »Comment on GotW #93: Auto Variables, Part 2 by mttpd
David: it’s not necessarily less safe, since the following assumption may not hold (it is not guaranteed): “presumably then `w` is a functioning `widget`.” That being said, your “As long,,,” explanation also applies to the object slicing problem and is a nice description :-) Read More »Comment on GotW #92 Solution: Auto Variables, Part 1 by Amali
@Herb, Comment on GotW #92: Auto Variables, Part 1 by David Thomas
delete this [pre]monspaced[/pre] Read More »Comment on GotW #92: Auto Variables, Part 1 by David Thomas
@herb: wordpress supports <code> in comments so folks can add code inline to prose. Read More »Comment on GotW #92: Auto Variables, Part 1 by David Thomas
delete this monospaced - word with and IRead More » Comment on GotW #92: Auto Variables, Part 1 by David Thomas
This is a crazy test Comment on GotW #92 Solution: Auto Variables, Part 1 by Amali
The image was blocked in my system, now I can see the image. Read More »Comment on GotW #92 Solution: Auto Variables, Part 1 by nosenseetal
@Herb | ||||
| ||||
Saturday, June 8, 2013
FeedaMail: Comments for Sutterâs Mill
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment