News for hackers. Stuff that matters.
Re:An Idiot's Guide to C++ Templates - Part 1 by btilly on Tuesday April 23, 2013 @08:21AM (#5594606)
In my (deliberately) limited C++ experience, I'm basically able to dream up how a program would work in a scripting language, translate all of the datatypes that I'm used to like growable arrays to STL equivalents (std::vector< ... > and std::map< ... > cover most of my use cases), and then after much verbosity and debugging, I get a magically fast program.

However the biggest frustration for me (aside from the verbosity) is that things work until they suddenly don't work, and then it isn't obvious why they don't work from the debugging stack you get back. They often don't work for good reason - but unless you're a C++ expert you don't know that reason.

For example suppose that I have a class that has reference members. Those are fields specified with & - they are kind of like a pointer except that you can't change them, and you use . instead of ->. Because you can't change them, operator= is not generated for you. I didn't notice this until I tried to use one in an std::map< ... > and everything blew up.

However luckily confusing backtrace message plus google usually leads to a useful stack overflow answer, else I'd find this process much more painful.

My one remaining frustration is that I hate how the STL did iterators. In the STL, if you have a data_type< foo > template, you iterate over it with a data_type< foo >::iterator. So you get a std::vector< foo >::iterator, a std::set< foo >::iterator, a std::dequeue< foo >::iterator, etc.

This is great for the compiler, but as a programmer it is backwards. I don't care what kind of data structure this came from, I care what kind of data type I get out. I'd like to see those three examples produce an iterator< foo >. And then you can dream up things like the ability to take an iterator< foo > and a method on foo that will return a bar, to get an iterator< bar >. I am used to having map/grep/etc, and it would be nice to be able to translate list-oriented thinking into C++ with less verbose boilerplate.

Re:An Idiot's Guide to C++ Templates - Part 1 by compusa on Tuesday April 23, 2013 @08:52AM (#5594740)
> For example suppose that I have a class that has reference members. Those are fields specified with & - they are kind of like a pointer except that you can't change them, and you use . instead of ->. Because you can't change them, operator= is not generated for you. I didn't notice this until I tried to use one in an std::map< ... > and everything blew up.

This is what std::reference_wrapper is for.

> I don't care what kind of data structure this came from

Fortunately, neither does the STL.

for_each(begin(foo_container), end(foo_container), some_foo_op);

Do you know what kind of container foo_container is? It doesn't matter. It can be a set, vector, list, or even a plain array.

> And then you can dream up things like the ability to take an iterator< foo > and a method on foo that will return a bar, to get an iterator< bar >

You can do this with std::transform.

transform(begin(foo_container), end(foo_container), begin(bar_container), op_to_make_foo_into_bar);

edit: I see from your other response that what you actually want is streams or generators, not an iterator.

Re:An Idiot's Guide to C++ Templates - Part 1 by btilly on Tuesday April 23, 2013 @09:05AM (#5594817)
As I said, my C++ experience is limited.

Thank you for demonstrating a better way to do it. Hopefully I'll remember that the next time that I need it. (Which is likely to be several years from now.)

Also you're right that I would like streams and generators. But, to me, it is the same abstraction as iteration. See, for instance, how Python does it.

Re:An Idiot's Guide to C++ Templates - Part 1 by marblar on Tuesday April 23, 2013 @09:18AM (#5594894)
You should check out the boost iterator library. Depending on the application, you might be looking for either the function input iterator or the counting iterator.
Re:An Idiot's Guide to C++ Templates - Part 1 by btilly on Tuesday April 23, 2013 @09:33AM (#5594994)
I have avoided learning boost for the simple reason that on the rare occasions when I need C++, it has been apparent to me that I could easily spend longer trying to evaluate whether anything that is available would be a good fit for my problem, than it would take to be done.

Put another way, the effort of learning something needs to be amortized over all of the times that you'll likely use that knowledge. I use C++, rarely enough that I won't get much amortization. (And when I do use it, it is painful enough that I don't want to explore it just for personal enjoyment. Leading to my avoiding C++...)

Re:An Idiot's Guide to C++ Templates - Part 1 by minimax on Tuesday April 23, 2013 @10:11AM (#5595195)
"However luckily confusing backtrace message plus google usually leads to a useful stack overflow answer, else I'd find this process much more painful."

Template related error messages have historically been a huge pain, but modern versions of Clang and g++ are doing a much better job than they used to. If you haven't tried C++ recently (say last year or two), you might try again with a newer version of Clang.

Re:An Idiot's Guide to C++ Templates - Part 1 by jevinskie on Tuesday April 23, 2013 @08:47AM (#5594714)
The iterator typing is much improved in C++11. It's just auto adt.begin().
Re:An Idiot's Guide to C++ Templates - Part 1 by btilly on Tuesday April 23, 2013 @08:59AM (#5594781)
There is less verbose repeating of verbosity. But the types did not change in anything like the way that I would like.

Try to translate http://perl.plover.com/Stream/stream.html into C++ iterators to see how the current abstraction limits the ways you can think about a program. By contrast suppose that my hypothetical iterator< foo > type was required to have a pointer overload, and supported the methods done() and next(). Now go back and try to translate that article - you'll find that it is pretty easy.

Re:An Idiot's Guide to C++ Templates - Part 1 by X-Istence on Tuesday April 23, 2013 @12:23PM (#5596087)
Instead of me trying to understand Perl, tell me what problem you are trying to solve that having an hypothetical iterator<foo> would help solve.
Re:An Idiot's Guide to C++ Templates - Part 1 by btilly on Tuesday April 23, 2013 @12:35PM (#5596173)
The interface that I describe can be backed by a collection, data streamed externally (eg from a file), or by something generated on the fly. Therefore you can write code for all three cases that looks very similar.

That article demonstrated the power of this idea by writing code that fairly efficiently generates the Hamming sequence, which consists of all positive integers whose only divisors are 2, 3, and 5. (So 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, ...)

Re:An Idiot's Guide to C++ Templates - Part 1 by X-Istence on Tuesday April 23, 2013 @12:52PM (#5596277)
You can create your own type of iterator that when dereferenced spits out the next number/item, So long as your "end" iterator never matches your "current" iterator it will continue going on. Your "done" function is when "current" and "end" match. "next()" is "++current".
Re:An Idiot's Guide to C++ Templates - Part 1 by reddit_clone on Tuesday April 23, 2013 @12:43PM (#5596222)
Indeed. First off, it is unrealistic to expect to rewrite perl/python scripts (much higher level scripting languages) in C++ and expect the same level of succinctness.

C++ is for larger , high performance applications.

The piper needs to be paid one way or another. If you rewrite a perl script in C++ for performance, the relative increase in verbosity is the price you pay.

Re:An Idiot's Guide to C++ Templates - Part 1 by btilly on Tuesday April 23, 2013 @04:22PM (#5597720)
I accept that a price has to be paid for performance.

However I believe that a substantial amount of verbosity could be removed without impacting said performance. In fact C++11 removes some with type deduction.

I also get tired of typing some_big_type foo = some_big_type(); - is there a way to say, "I want this thing, and I want it to get the obvious default initialization?" Because what I type now is straight from the redundant department of redundancy department. (Yes, a typedef can make that shorter. You still write the idea twice.)

Re:An Idiot's Guide to C++ Templates - Part 1 by mpyne on Tuesday April 23, 2013 @09:50PM (#5599185)
Try auto foo = some_big_type();

If you're not talking about initialization, but instead talking about construction, just do some_big_type foo; (no parens needed).

Re:An Idiot's Guide to C++ Templates - Part 1 by btilly on Thursday April 25, 2013 @12:00AM (#5605638)
If you're not talking about initialization...

I thought I was very clear when I said: "I want this thing, and I want it to get the obvious default initialization?"

I often wound up typing something like this:

std::vector< my_big_type > list_foo = std::vector< my_big_type >();

It seemed useless the first time, and just got sillier as time went on.

Re:An Idiot's Guide to C++ Templates - Part 1 by X-Istence on Wednesday April 24, 2013 @03:29AM (#5600301)
some_big_type foo;

Now foo has been created.

Want to pass parameters to its constructor:

some_big_type foo(parameters, go, here);

foo has been initialised.

Need a pointer?

auto *foo = new some_big_type foo(parameters, go, here);

Re:An Idiot's Guide to C++ Templates - Part 1 by vinkelhake on Tuesday April 23, 2013 @12:01PM (#5595954)
The thing about a "generic" iterator is that not all iterators have the same capabilities. So while you might not care about the difference between a bidirectional iterator and a random access iterator, there are people who do and algorithms that can be implemented much more efficiently with the right iterator capabilities.

There are examples of iterators that use type erasure, but they still incorporate the iterator category in the type.

Re:An Idiot's Guide to C++ Templates - Part 1 by plorkyeran on Tuesday April 23, 2013 @09:20AM (#5594914)
any_range covers the use-case of a generic iterator that doesn't care about the source: http://www.boost.org/doc/libs/1_53_0/libs/range/doc/html/ran...

In practice, it's not really useful all that often. It has non-zero overhead so it's not good default choice, and you rarely absolutely need it. Most situations where you'd want to return a value then do something with it can be transformed into passing a callback to the function instead, which lets you use a templated operator() to achieve the same result without the runtime overhead.