Re:Simple Trie Implementation in C++11
by imedadel on Sunday July 21, 2019 @03:33PM
(#20493202)
On a side note, I recently started competitive programming in my college, and while preparing for the upcoming xCPC competitions, I was wondering if I should use "auto" and a more functional approach in C++ (instead of using int, double, etc. and OOP). What do you think?
[ Parent
| on HN ]
You mean for competitions, or in general? For competitions, go with whatever is faster/reduces your typing. In general, I think a lot of people would the same thing, but I'm in the (apparently small?) camp that thinks auto is massively overused. I use typedefs liberally instead of using auto all over the place. It prevents some implicit casts from being inhibited (which are rare, but which can cause correctness issues), and it documents things better. The cost is more typing, which in my view is just something you have to learn C++ is not intended to minimize.
I think typing isn't my issue (so far), but rather the performance. On one hand, it's one less thing to think about while figuring out a problem, but on the other hand, it might reduce the performance of my solution, and in that case, going back and refactoring the code to use the correct types would be a waste of time...
You seem to have a misconception of what `auto` entails... It just means "deduce type from the right-hand side of the assignment statement", instead of having to type it explicitly. Doesn't make your program dynamically typed or runtime typed all of a sudden.
Oh interesting. Why do you think auto would affect run-time performance? Could you describe an example?
I think auto won't have any run-time performance since type deduction happens at compile-time.
Also read this https://stackoverflow.com/questions/19618759/c-11-auto-compi...
I'm already well aware of this. I'm asking why the OP thinks otherwise. It's not outright impossible to make it affect performance [1] but I'm trying to see what the concern is.
[1] Like by taking the approach that results in a cast, e.g. here: https://news.ycombinator.com/item?id=20493263
Oh, I see. I didn't know that type deduction happens at compile-time :o
Yeah, that's how type systems work in most languages. That's why we have them: they prevent mistakes before you even run your code :)
Why would you think that using auto would reduce the performance of your code?
I usually explicitly type my integer constants based on the problem description (e.g. if N < 1e9 I would use int_fast32_t) and then let auto/decltype do most of the work after that.
I don't like auto over int, and other primitives. But auto in for loops or with iterators seems the way to go and is a bless!
With begin()/end() it's probably fine, but for-each loops it's not a great idea since then you run into problems when there was a cast intended. The main (only?) example of this pattern in the standard is vector<bool>, so of course people's immediate reaction to blame this on vector<bool>. However that's just the example currently in the standard, and people use it for other things too. By using auto you end up writing code that can break. Example:
typedef std::vector<bool> Vec;
Vec f(1, false);
for (typename Vec::value_type &&x : f) { std::cout << typeid(x).name() << std::endl; }
for (auto &&x : f) { std::cout << typeid(x).name() << std::endl; }Do you have examples of cases other than vector<bool> where this is an issue?
Thanks, those were interesting to read about. It doesn't seem like something that would come up in the for loop case, though.
I mean, you can imagine proxies for stuff beside bools and matrices...
template<class It> struct iterator_range { It b, e; It begin() const { return b; } It end() const { return e; } };
template<class It> iterator_range<It> make_iterator_range(It b, It e) { iterator_range<It> r = { b, e }; return r; }
template<class T> struct endian_reversed_iterator {
T *p;
struct reference {
T *p;
operator T() const { return boost::endian::endian_reverse(*p); }
reference &operator =(T const &other) const { *p = boost::endian::endian_reverse(other); }
};
endian_reversed_iterator(T *p) : p(p) { }
reference operator *() { reference r = { p }; return r; }
endian_reversed_iterator &operator++() { ++p; return *this; }
bool operator!=(endian_reversed_iterator const &other) const { return p != other.p; }
};
int main() {
unsigned arr[] = { 1, 2 };
for (auto x : make_iterator_range<endian_reversed_iterator<unsigned> >(&arr[0], &arr[2])) {
++x; // whatever
}
}That's what I've been doing. My issue is whether using auto would affect performance.
Just keep in mind that auto is different than const auto. Performance won't be an issue.
Personally, I use auto only when I have to write a long typename (ex. Iterators).
And what about object-oriented programming vs functional programming? Performance-wise, that is.