What are the new features in C++0x and how do they work?

  • C/C++
  • Thread starter Grep
  • Start date
  • Tags
    Tires
In summary: The compiler can infer the type of the variable from the initializer. So far, this feature has worked great for me.Another cool feature is the ability to use C++11's std::initializer_list<T> in your code. std::initializer_list<int> list;This declares a list of ints which will be initialized to the values 1, 2, 3, etc. I also like the new std::chrono::steady_clock type.std::chrono::steady_clock const{42};This declares a constant steady_clock which will keep track of the current time in seconds.
  • #1
Grep
298
3
The Final Draft of the standard for the next version of C++ (referred to as C++0x) was just completed, it seems. There are other things to do before it's official and completed, but it's a big milestone. So I was curious what was available in the GCC compiler from the new spec. There's a list here:

http://gcc.gnu.org/projects/cxx0x.html

Quite a bit, really, in fact. Some useful stuff was available with version 4.4 of gcc, which I had installed on my Linux system. But I soon wanted to see some of the features in the new 4.6 version, so I compiled that. So far, so good.

I thought it might be interesting for others if I show you some of the features that I like the best so far. But really, initialization lists and ranged for loops would be enough to get me excited. Anyways, this gives you a chance to take a peek at the new features and see an example of how they work. If that doesn't interest you, read no further.

I installed gcc-4.6.0 in my home directory so I don't mess anything up, and I'll briefly go over how I get my test program to compile and run. It's a super simple setup, so don't expect much. I have one source file called Main.cpp which I compile with this (putting your home directory where I marked, and making sure the CC variable is your compiler binary):
Code:
GCC_HOME=${HOME}/gcc-4.6.0
PATH := ${GCC_HOME}/bin:${PATH}
LD_LIBRARY_PATH := ${GCC_HOME}/lib
LD_RUN_PATH := ${LD_LIBRARY_PATH}
CC=g++-4.6
CFLAGS=-std=c++0x

all:
        ${CC} ${CFLAGS} Main.cpp -o Main

I also ran these two lines in the shell before running the program:
Code:
export PATH=${PATH}:$HOME/gcc-4.6.0/bin
export LD_LIBRARY_PATH=$HOME/gcc-4.6.0/lib

To get someone up and running quickly, this is the main part of the test program in Main.cpp:
Code:
#include <iostream>
#include <vector>
#include <list>
#include <array>
#include <tuple>
#include <algorithm>
#include <chrono>
#include <ratio>

using namespace std;

void testAuto();
void testRangeFor();
void testEnumClasses();
void testInitializerLists();
void initListFunc(initializer_list<int> list);
void arrayTest();
void testTuple();
void testTime();
void testLambda();
void testNullptr();int main(int argc, char *argv[])
{
   // Add calls to test functions here

   return 0;
}

Now I'll just go through the explanatory test functions one by one. To run each function, just call it from the previous program's main function.

Possibly my second favorite new feature is the initializer list. A long time in coming. It's so far been annoying to initialize a vector or similar container with a static list of values. You end up either making an array initialized properly, and using it to construct a vector, or you use push_back() or similar on each element. Yuck.

Not any more! Behold!
Code:
void testInitializerLists()
{
   vector<double> v = { 1, 2, 3.456, 99.99 };

   cout << "--- Initializer Lists ---\n";
   cout << "v[1] = " << v[1] << '\n';
   cout << "Max of {1, 5, 10, 6, 3} = " << max({1, 5, 10, 6, 3}) << '\n';

   list<pair<string,string>> languages = {
       {"Nygaard","Simula"}, {"Richards","BCPL"}, {"Ritchie","C"}
   };
   list<pair<string,string>>::iterator it;
   for (it = languages.begin(); it != languages.end(); it++)
   {
      // OOOOOOH, a cleaner way to access pair/tuple types, nice...
      cout << get<0>(*it) << " -> " << get<1>(*it) << endl;
   }
   initListFunc({1, 2, 3, 5, 6 , 7, 9});
}

void initListFunc(initializer_list<int> s)
{
   for (auto p = s.begin(); p != s.end(); ++p)
   {
      cout << *p << '\n';
   }
}
I would also draw your attention to the way I accessed the variables in the pair. Normally, we'd have to use it->first and it->second. That get is also usable in the new tuples, which I'll get to later.

Also note that max() now accepts initializer lists as well. I'll get to 'auto' soon.

Which leads into my current favorite new feature: Ranged for. Wow, how I miss it when I use C++. It was one of the nicer new features in java when it was introduced. The normal way of using iterators is a bit verbose and unnecessary, I think.

This, on the other hand, I like:
Code:
void testRangeFor()
{
   vector<int> list = {2, 42, 53, 137};

   cout << "--- Range for of vector<int> ---\n";
   for (int x : list)
   {
      cout << dec << x << '\n';
   }

   cout << "--- Range for of static ints ---\n";
   for (auto x : {1,2,3,5,8,13,21,34 })
   {
      cout << dec << x << '\n';
   }
}

Also really handy is the new auto type. Auto works like this:
Code:
void testAuto()
{
   int a = 43;
   double b = 203.3;

   auto x = a * b;

   cout << "--- auto type ---\n";
   cout << a << " * " << b << " = " << x << std::endl;
}
Though I'll probably used ranged for more than iterators now, auto can clean up an iterator. Look at the one I used to go through the 'languages' list in testInitializerLists(), above. It can be written:
Code:
for (auto it = languages.begin(); it != languages.end(); it++)
{
   ... etc ...
Somehow I get the feeling auto may be abused, though, but that's C++ for ya.

Enum classes are also of interest:
Code:
void testEnumClasses()
{
   enum EE : unsigned long { EE1 = 1, EE2 = 2, EEbig = 0xFFFFFFF0U };
   enum class Color : unsigned long {red = 0xFF0000, green=0x00FF00,
                                     blue=0x0000FF};
   cout << "--- Enum classes ---\n";
   cout << EE1 << endl;
   cout << "0x" << hex << EEbig << endl;
   Color col = Color::red;
   cout << "Color RGB: 0x" << (unsigned long)col << endl;
   switch (col) {
   case Color::red:
      cout << "RED" << '\n';
      break;
   case Color::green:
      cout << "GREEN" << '\n';
      break;
   case Color::blue:
      cout << "BLUE" << '\n';
      break;
   default:
      break;
   }
   cout << dec;
}
I do like the way the actual underlying type of the enum can be specified, and the scoping (i.e. It's not 'red' it's 'Color::red').

And then there's the tuples, which are sure to come in handy:
Code:
void testTuple()
{
   // t will be of type tuple<string,int,double>
   auto t = make_tuple(string("Herring"),10, 1.23);

   cout << "--- tuple ---\n";
   string s = get<0>(t);
   int x = get<1>(t);
   double d = get<2>(t);

   cout << "tuple<\"" << s << "\", " << x << ", " << d << ">" << endl;
}

Also in my list of top new features is Lambda. Let's say you're trying to sort a vector, but you want to use your own comparator. Annoying, right? Easy now:
Code:
void testLambda()
{
   vector<int> v = {50, -10, 20, -30};

   cout << "--- Lambda ---\n";

   sort(v.begin(), v.end());    // the default sort
   // now v should be { -30, -10, 20, 50 }
   cout << "List: ";
   for (auto el : v)
   {
      cout << " " << el;
   }
   cout << endl;

   // sort by absolute value:
   sort(v.begin(), v.end(), [](int a, int b) { return abs(a)<abs(b); });
   cout << "List after sort by absolute value with lambda: ";
   for (auto el : v)
   {
      cout << " " << el;
   }
   cout << endl;
}
See how easy it was to define a new comparator to make it sort by absolute value? A vast improvement, in my opinion. Doing that previously just seemed to be more difficult than it should have been.

We also have a new array type, for fixed-size arrays:
Code:
void arrayTest()
{
   cout << dec << "--- Array test ---\n";
   array<int,6> a = { 1, 2, 3 };
   a[3]=4;
   for (int i = 0; i < a.size(); i++)
   {
      cout << "a[" << i << "] = " << a[i] << '\n';
   }
   cout << "Sum: " << accumulate(a.begin(), a.end(), 0) << endl;
}

They've also added new time functionality. Of course, there's always the Boost libraries, but these will come in handy:
Code:
void testTime()
{
   using namespace std::chrono;
   microseconds mms(12345);
   milliseconds ms(123);
   seconds s(10);
   minutes m(30);
   hours h(34);

   cout << "--- time ---\n";
   auto x = hours(2) + minutes(35) + seconds(9);
   cout << "Duration of 2:35:09 in seconds (should be 9309) = " << duration<double>(x).count() << endl;
   cout << " Or in decimal hours: " << duration<double,ratio<3600,1>>(x).count() << " hours\n";

   auto t = monotonic_clock::now();
   for (int i = 0; i < 1000000; i++); // waste time
   auto d = monotonic_clock::now() - t;
   cout << "1,000,000 useless iterations took " << duration<double>(d).count() << " seconds\n";
}

For the last feature, it's one I've always missed, and it's a simple one. They added 'nullptr' to represent a null pointer value. I know right? Earth. Shattering.
Code:
void testNullptr()
{
    cout << "--- nullptr ---\n";
    int *p = nullptr;
    if (p == nullptr)
    {
        cout << "p is a nullptr\n";
    }
}

Well, that's where I'm at so far. There's plenty more features, but that's plenty for one post. Hope that was actually interesting to someone here! I'm sure many of you use C++, and that's going to be the standard soon enough.

I should mention that snippets were taken from Bjarne Stroustrup's FAQ on C++0x at:

http://www2.research.att.com/~bs/C++0xFAQ.html
 
Last edited:
Technology news on Phys.org
  • #2
Very interesting!
Thanks for the report, Grep.
 
  • #3
The initializer list for vectors etc. is something I really wish C++ had when I was teaching it some years ago.

Alas, it looks like Apple's Xcode Tools is not going to go beyond gcc 4.2, so if I want to get in on the fun with 4.6 I'll have to compile it from source.
 
  • #4
Mark44 said:
Very interesting!
Thanks for the report, Grep.

Glad you liked it!

jtbell said:
The initializer list for vectors etc. is something I really wish C++ had when I was teaching it some years ago.

Alas, it looks like Apple's Xcode Tools is not going to go beyond gcc 4.2, so if I want to get in on the fun with 4.6 I'll have to compile it from source.

Yep, love initializer lists!

Not sure if Xcode makes it more complicated, but compiling gcc 4.6.0 on Linux was 100% painless as long as the install docs are read and followed. I would hope it wouldn't be much worse on Mac. Wouldn't put any money down on it, but I'd hope!

I did find one page from someone who compiled it on Mac who put up what he did. Looks like you might have to compile some of the prerequisites before gcc. In case it comes in handy:

http://www.coding.com.br/mac/building-gcc-4-6-on-macosx/ [Broken]

Just keep in mind the '--' characters in some of his commands are messed up. Also, he got it from SVN, but you'd probably want the released tarball from http://gcc.gnu.org instead.
 
Last edited by a moderator:
  • #5
Here's a source for gcc 4.6 pre-compiled for Mac OS X 10.6:

http://hpc.sourceforge.net/

I've previously installed his binary package for gfortran and it seems to work OK. I'll try his gcc when I get some free time.
 
  • #6
Thanks for taking the time to show us all those examples.

For future reference: It's generally bad to install to you home directory (or anywhere else) as a normal user; it leaves your executables vulnerable to being patched. The generally accepted place to install stuff is in /usr/local/(unique name here).
 
  • #7
TylerH said:
Thanks for taking the time to show us all those examples.

For future reference: It's generally bad to install to you home directory (or anywhere else) as a normal user; it leaves your executables vulnerable to being patched. The generally accepted place to install stuff is in /usr/local/(unique name here).

No problem Tyler, glad to see at least a few people found it interesting.

As for installing in my home directory, it's the perfect place to install if you think you might want to delete it later. There's no make uninstall for gcc. But it seems to work nicely, so it'll probably get it installed to /usr/local soon enough.

If anything, my system is secured far more than necessary so it's not likely to be an issue. I've been tinkering and developing with Linux since 1993, and you could say making it secure is part of the fun for me. So it's unlikely to ever be an issue in this case. Still generally good advice though!
 
  • #8
jtbell said:
Here's a source for gcc 4.6 pre-compiled for Mac OS X 10.6:

http://hpc.sourceforge.net/

I've previously installed his binary package for gfortran and it seems to work OK. I'll try his gcc when I get some free time.

I just installed it on my Mac at work, putting everything into /usr/local. It works fine after I tweaked my PATH to put /usr/local/bin at the beginning so "g++" invokes 4.6 by default instead of 4.2 from Xcode tools. I also have to specify the standard in the compilation command:

Code:
g++ -std=c++0x initializer.cpp
 
  • #9
Grep said:
The Final Draft of the standard for the next version of C++ (referred to as C++0x) was just completed, it seems.
Nice job, Grep.

What I like:
  • default and delete.
    A lot of times I don't need a copy constructor or assignment operator. A lot of times I don't even know what copying what is inherently an un-copyable object even means. The "solution" in the current implementation is to declare the copy constructor and assignment operator private and (whoops) fail to provide an implementation. A couple of problems with this:
    • Normally the private part of a class is at the tail end of the class definition. Not these guys. A user of a class needs to know that the copy constructor or assignment operator are not available.
    • When someone does invoke one of these unimplemented methods, the error message is extremely non-intuitive. (Link error).

    A related problem occurs with virtual destructors: All I want is the default behavior, except the default is not virtual. C++0x fixes these problems, and it adds a whole lot of new toys with that solution. Very nice.

  • I won't bother going over that long list of features to which you already provided a link except for one: Simplified iteration. You went over this, Grep, but dang, that is nice.


What I don't like:
  • Still no exponentiation operator. This is one of the big http://pragmatic.nationalinterest.in/2008/09/05/gok-4-coffee-stains-tea-cups [Broken] that make some stick with Fortran rather than convert to C/C++.
  • The mathematical functions in TR1 are not going to be a part of c++0x?? This lack of support for scientific programming is yet another reason some stick with Fortran.

I switched from Fortran to C (and then C++) almost twenty years ago. There are times when I see the points raised by my cohorts who have stuck with Fortran.
 
Last edited by a moderator:
  • #10
Ranged for works with both new and old style arrays!

Code:
//  Let's try this with a new-style array.

    array<double,4> a = {1.1, 2.2, 3.3, 4.4};

    cout << "New Array: ";
    for (double x : a)
    {
        cout << x << ' ';
    }
    cout << endl;

//  Can we do it with an old-style array? Yes!

    double a2[4] = {1.1, 2.2, 3.3, 4.4};

    cout << "Old Array: ";
    for (double x : a2)
    {
        cout << x << ' ';
    }
    cout << endl;
 
  • #11
D H said:
Nice job, Grep.

What I like:
  • default and delete.
Thanks D H! And I do like those features as well. Could have gone on with more features, but figured the post was long enough.

Another nice feature is delegating constructors. Alas, that is not yet implemented in gcc. Also looking forward to the thread/concurrency support, which is also not yet implemented. And I haven't yet looked at the rvalue stuff.

D H said:
I won't bother going over that long list of features to which you already provided a link except for one: Simplified iteration. You went over this, Grep, but dang, that is nice.
I know it! I value clean, comprehensible code. C++ sometimes fails to deliver, but that's a feature that cleans it up quite a bit.

D H said:
What I don't like:
  • Still no exponentiation operator. This is one of the big http://pragmatic.nationalinterest.in/2008/09/05/gok-4-coffee-stains-tea-cups [Broken] that make some stick with Fortran rather than convert to C/C++.
  • The mathematical functions in TR1 are not going to be a part of c++0x?? This lack of support for scientific programming is yet another reason some stick with Fortran.

I switched from Fortran to C (and then C++) almost twenty years ago. There are times when I see the points raised by my cohorts who have stuck with Fortran.

I suspect those comments will garner quite a lot of support in these forums, myself included! This has bothered me quite a bit. It's just kind of sad to have any reason to stick with a language like Fortran after this long. They, in fact, made a conscious decision not to add scientific programming support for this spec. Possibly the only thing that really annoys me about the new spec.

I could go on a rant, but suffice to say I agree with you 100%.

jtbell said:
Ranged for works with both new and old style arrays!
Didn't even think to try, thanks for pointing that out. Outstanding!
 
Last edited by a moderator:
  • #12
When I saw the "ranged for", I thought, "This reminds me of something." I finally remembered it: "foreach" in Perl:

Code:
print "Array contents: ";
foreach $item (@myArray)
{
    print "$item ";
}
print "\n";
 
  • #13
Yep. And for loops in python. And in bash. And in csh. Lot's of languages have that. Nice to see it added to c++.
 
  • #14
Does anyone here use boost? Some features of C++0x make some boost libraries obsolete. Should those who use these boost libraries continue to do so since C++0x is backwards compatible or should we be abandoning these obsolete libraries?

It's a shame that all the effort put into some of these boost libraries are, in a sense, wasted...
 
  • #15
Jocko Homo said:
Does anyone here use boost? Some features of C++0x make some boost libraries obsolete. Should those who use these boost libraries continue to do so since C++0x is backwards compatible or should we be abandoning these obsolete libraries?

It's a shame that all the effort put into some of these boost libraries are, in a sense, wasted...
Many of the standard library additions came directly from Boost. How's that a waste?

If there's a good Boost library, use it. If a lot of people use it, chances are, it'll be part of C++1x.
 
  • #16
Grep said:
They, in fact, made a conscious decision not to add scientific programming support for this spec. Possibly the only thing that really annoys me about the new spec.
On the other hand, they at least did make the c99 math library part of the new standard, and very much in their favor, there is this neat new header <random>.


Jocko Homo said:
It's a shame that all the effort put into some of these boost libraries are, in a sense, wasted...
Wasted? Those efforts were anything but wasted! Having the Boost libraries (or parts thereof) incorporated into some future standard is one of the explicit goals of the Boost project.
From http://www.boost.org:
We aim to establish "existing practice" and provide reference implementations so that Boost libraries are suitable for eventual standardization.
 
  • #17
D H said:
On the other hand, they at least did make the c99 math library part of the new standard, and very much in their favor, there is this neat new header <random>.

Very true! Gave getting that going another try. At least some parts of the new random functionality is still found only in tr1, and appears not to have been rolled into the C++0x libraries yet. Looks nice though!

I whipped up a quick test function.

You need to include <tr1/random> for this functionality, for now.

Code:
int rand_int(int low, int high)
{
   using namespace std::chrono;
   auto engine = default_random_engine();
   auto t = monotonic_clock::now();
   engine.seed(t.time_since_epoch().count());

   static tr1::variate_generator<default_random_engine, tr1::uniform_int<>> r {engine,tr1::uniform_int<>(low,high)};
   return r();
}

Of course, keep in mind I'm seeding it every single time the function is called, when it should be seeded once at the start. But I refuse to "pull a Sony" and initialize it with a static number. :wink:

And we won't mention a bit of 'auto' abuse, will we? Well, it *is* just for demonstration purposes.

You can call it like this:

Code:
   cout << "Random int from 1 to 6: " << rand_int(1, 6) << endl;

The meat of the rand_int function was taken from the C++0x FAQ.

EDIT: I should mention that this seeding method is still not adequate for cryptographic use.
 
Last edited:
  • #18
But the Mersenne Twister should be adequate for most simulation usages.
 
  • #19
D H said:
But the Mersenne Twister should be adequate for most simulation usages.
Indeed, and there's a few others in there as well, I notice.

One thing I love is the distribution classes they provide (from TR1 so not sure if they all made it in, but I'd guess so). TR1 has:
  • bernoulli_distribution
  • binomial_distribution
  • exponential_distribution
  • gamma_distribution
  • geometric_distribution
  • normal_distribution
  • poisson_distribution
  • uniform_int
  • uniform_real

Now that could come in handy!
 
  • #20
I don't think people have understood my concern about wasted effort in Boost...

For instance, who is going to continue using BOOST_FOREACH while C++0x's for loop construct now does the same thing? Will people go back to old code replacing instances of BOOST_FOREACH with the new for loop? Will people switch if their code already has BOOST_FOREACH all over it? Will the Boost libraries deprecate BOOST_FOREACH now that it essentially does nothing?

Isn't it a bit of a shame that all the effort put into BOOST_FOREACH is wasted now that it's obsolete?

These are the kinds of concerns I was having...
 
  • #21
Well, we got use of BOOST_FOREACH for a long period of time when it wasn't available in the stock C++ spec. That wasn't wasted. And we still get to use it while compilers implementing the spec become more generally available, since using it now still limits the compilers that will be able to compile our code.

So no, I don't think that effort was wasted at all. Sure, it would have been better had these new features been in the C++ standard already. But we're imperfect people living in an imperfect world. What can you do.
 
  • #22
Grep said:
Well, we got use of BOOST_FOREACH for a long period of time when it wasn't available in the stock C++ spec. That wasn't wasted. And we still get to use it while compilers implementing the spec become more generally available, since using it now still limits the compilers that will be able to compile our code.

So no, I don't think that effort was wasted at all. Sure, it would have been better had these new features been in the C++ standard already. But we're imperfect people living in an imperfect world. What can you do.
Point well taken but this reminded me of something else about the new for loop construct...

It's kind of wrong, isn't it? I mean, it's now a keyword that inspects structures for specific identifier names and evaluates them! Isn't that kind of odd for C++? Those names were previously only enforced by programmer convention and now keywords will rely on them... It's a paradigm shift similar to moving to syntactic indentation (like in Python)!

Meanwhile, BOOST_FOREACH did work...
 
  • #23
Jocko Homo said:
Point well taken but this reminded me of something else about the new for loop construct...

It's kind of wrong, isn't it? I mean, it's now a keyword that inspects structures for specific identifier names and evaluates them! Isn't that kind of odd for C++? Those names were previously only enforced by programmer convention and now keywords will rely on them... It's a paradigm shift similar to moving to syntactic indentation (like in Python)!

Meanwhile, BOOST_FOREACH did work...
Are you referring to "auto"? auto doesn't rely on anything but being initialized. It(really the compiler) determines the type it should be automatically based on how it is initialized.
 
  • #24
Jocko Homo said:
Point well taken but this reminded me of something else about the new for loop construct...

It's kind of wrong, isn't it? I mean, it's now a keyword that inspects structures for specific identifier names and evaluates them!
As noted above, it appears that you are talking about the "auto" keyword, not the "for" keyword. This new duck-typing use of the auto keyword will work quite nicely in old-style for loops as well:
Code:
for (auto iter = foo.begin(); iter != foo.end(); ++iter) {
   auto elem = *iter;
   do_something(elem);
}

There is nothing forcing you to use the "auto" keyword. You can still be explicit on types if you wish (or if your project has balked at this new use and banned the use of "auto").
Meanwhile, BOOST_FOREACH did work...
It worked if you had access to the Boost libraries and if the use was allowed on your project. Lots of projects, for various reasons, ban the use of the Boost libraries.

As far as the Boost project are concerned, this new language feature motivated by BOOST_FOREACH is a very big win for the project. One of the key goals of Boost is to have elements of the project become part of the next standard. BOOST_FOREACH, as the all-caps name suggests, is a macro. There are lots of pitfalls associated with this fact. This new for loop syntax is now a part of the language. Making this a part of the language as opposed to a macro is not just a win, it is a very big win.
 
  • #25
TylerH said:
Are you referring to "auto"? auto doesn't rely on anything but being initialized. It (really the compiler) determines the type it should be automatically based on how it is initialized.
What?! I feel like I've just walked into The Twilight Zone, that's how shocked I am that no one seems to understand what I'm talking about. I'm also insulted (although I recognize that I probably shouldn't be) that people think I can mistake the auto keyword for a "for loop construct."

I'm talking about this:
Code:
std::vector<int> container = {1, 2, 3, 4};
for (int i: container) {
    // do something with i
}
How does this work? It works because the keyword for looks for the identifier names "begin" and "end" in the object identified by, in this case, "container." What? Really? Should it really be doing that?
 
  • #26
Oh... dang, you're correct. http://en.wikipedia.org/wiki/C++0X#Range-based_for-loop

What's bad about it relying on begin() and end()? Don't all iterator based foreach(the old way) loops use them anyway? I can see the fact that C++ is approaching Java is kinda scary, but perhaps Java didn't completely screw up; perhaps foreach is one nugget of the few out of the mine full of copperlites that is Java.

Not to question your obvious knowlegability again, but it wouldn't compile with a container without the begin and end symbols. That does remove a little of the uncertainty, I believe.
 
  • #27
D H said:
As noted above, it appears that you are talking about the "auto" keyword, not the "for" keyword. This new duck-typing use of the auto keyword will work quite nicely in old-style for loops as well:
Code:
for (auto iter = foo.begin(); iter != foo.end(); ++iter) {
   auto elem = *iter;
   do_something(elem);
}
I am very curious to know how on God's green Earth it could "appear" as if I'm talking about the auto keyword. Can you please explain this to me?

It worked if you had access to the Boost libraries and if the use was allowed on your project. Lots of projects, for various reasons, ban the use of the Boost libraries.

As far as the Boost project are concerned, this new language feature motivated by BOOST_FOREACH is a very big win for the project. One of the key goals of Boost is to have elements of the project become part of the next standard. BOOST_FOREACH, as the all-caps name suggests, is a macro. There are lots of pitfalls associated with this fact. This new for loop syntax is now a part of the language. Making this a part of the language as opposed to a macro is not just a win, it is a very big win.
You don't have to use Boost in particular. What Boost demonstrates is that you can do range-based for loops (as I now know they're called) with the language already. You didn't have to resort to language hacking...

With that said, yes, it does use a macro and this is less than ideal. However, it is a well behaved macro and it's not as if macros aren't an integral part of C++. Hell, the entirety of C++ libraries are implemented using the preprocessor...
 
  • #28
TylerH said:
Oh... dang, you're correct. http://en.wikipedia.org/wiki/C++0X#Range-based_for-loop

What's bad about it relying on begin() and end()? Don't all iterator based foreach(the old way) loops use them anyway? I can see the fact that C++ is approaching Java is kinda scary, but perhaps Java didn't completely screw up; perhaps foreach is one nugget of the few out of the mine full of copperlites that is Java.

Not to question your obvious knowlegability again, but it wouldn't compile with a container without the begin and end symbols. That does remove a little of the uncertainty, I believe.
Well yeah... It's not outrageously bad. It wouldn't have made it into the standard if it were...

I'm just suggesting that it's a little wrong... In particular, it's paradigm breaking. Previously, the C++ syntax was completely divorced from code semantics. For example, it didn't care what identifiers you chose as long as you used them consistently. That's why constructors and destructors used the class name instead of some keyword (that, and Bjarne wanted to minimize the number of keywords introduced by C++).

Seriously, didn't C++ constructor and destructor definitions seem redundant to you? How many times have you reconsidered the name of a class and then changed it? Didn't you wonder why you had to change the name of the constructors and destructor too, even though they remain semantically identical and are necessarily invoked by the name of the class (or not explicitly invoked at all)? If you fail to change the name of the destructor, you get the "hey, your destructor name doesn't match your class name" error message, which should seem odd 'cause if it knows that it doesn't match and that it should, couldn't it have just changed it for you and compile? ...but now I'm rambling...

They've now introduced a piece of C++ syntax that enforces specific identifier names after C++ had previously jumped through hoops to avoid this. It's paradigm breaking...
 
  • #29
Jocko Homo said:
I mean, it's now a keyword that inspects structures for specific identifier names and evaluates them! Isn't that kind of odd for C++?
operator+. :tongue:


The point of a practical programming language like C++ is to write programs, not to strive to achieve purity of form (if we could even agree on what that should be). This update was meant to fix shortcomings in the language; the overly verbose and redundant "for loop that iterates over a range" syntax was one of those shortcomings.
 
  • #30
Jocko Homo said:
I'm just suggesting that it's a little wrong... In particular, it's paradigm breaking.
How? The old syntax for for loops still works. for is now overloaded. If you don't like the new syntax, don't use it.

They've now introduced a piece of C++ syntax that enforces specific identifier names after C++ had previously jumped through hoops to avoid this. It's paradigm breaking...
Where? I don't get your objection.
 
  • #31
Jocko Homo said:
I am very curious to know how on God's green Earth it could "appear" as if I'm talking about the auto keyword. Can you please explain this to me?
Because it didn't look like you were talking about the for keyword. I still don't understand your objection.

You don't have to use Boost in particular. What Boost demonstrates is that you can do range-based for loops (as I now know they're called) with the language already. You didn't have to resort to language hacking...
In the eyes of many, using the preprocessor for anything but the standard one-time include guard (#ifndef NAME/#define NAME) and #include statements is language hacking. Abuse of the preprocessor is standard fare for the IOCCC. For your amusement / disgust, here's a winning IOCCC entry written by Jim Hague back in 1986 that translates ascii to Morse code, with the ascii text read from standard input:
Code:
#define	DIT	(
#define	DAH	)
#define	__DAH	++
#define DITDAH	*
#define	DAHDIT	for
#define	DIT_DAH	malloc
#define DAH_DIT	gets
#define	_DAHDIT	char
_DAHDIT _DAH_[]="ETIANMSURWDKGOHVFaLaPJBXCYZQb54a3d2f16g7c8a90l?e'b.s;i,d:"
;main			DIT			DAH{_DAHDIT
DITDAH			_DIT,DITDAH		DAH_,DITDAH DIT_,
DITDAH			_DIT_,DITDAH		DIT_DAH DIT
DAH,DITDAH		DAH_DIT DIT		DAH;DAHDIT
DIT _DIT=DIT_DAH	DIT 81			DAH,DIT_=_DIT
__DAH;_DIT==DAH_DIT	DIT _DIT		DAH;__DIT
DIT'\n'DAH DAH		DAHDIT DIT		DAH_=_DIT;DITDAH
DAH_;__DIT		DIT			DITDAH
_DIT_?_DAH DIT		DITDAH			DIT_ DAH:'?'DAH,__DIT
DIT' 'DAH,DAH_ __DAH	DAH DAHDIT		DIT
DITDAH			DIT_=2,_DIT_=_DAH_;	DITDAH _DIT_&&DIT
DITDAH _DIT_!=DIT	DITDAH DAH_>='a'?	DITDAH
DAH_&223:DITDAH		DAH_ DAH DAH;		DIT
DITDAH			DIT_ DAH __DAH,_DIT_	__DAH DAH
DITDAH DIT_+=		DIT DITDAH _DIT_>='a'?	DITDAH _DIT_-'a':0
DAH;}_DAH DIT DIT_	DAH{			__DIT DIT
DIT_>3?_DAH		DIT			 DIT_>>1 DAH:'\0'DAH;return
DIT_&1?'-':'.';}__DIT DIT			DIT_ DAH _DAHDIT
DIT_;{DIT void DAH write DIT			1,&DIT_,1 DAH;}


With that said, yes, it does use a macro and this is less than ideal. However, it is a well behaved macro and it's not as if macros aren't an integral part of C++. Hell, the entirety of C++ libraries are implemented using the preprocessor...
The entirety of C++ libraries are implemented using the preprocessor? Where did you get that idea? Most of the C++ library is in the form of templates. The preprocessor doesn't know beans about templates.
 
  • #32
Hurkyl said:
The point of a practical programming language like C++ is to write programs, not to strive to achieve purity of form (if we could even agree on what that should be). This update was meant to fix shortcomings in the language; the overly verbose and redundant "for loop that iterates over a range" syntax was one of those shortcomings.
You're assuming that C++ is a practical programming language...

I can understand sacrificing "purity of form" for a practical advantage but... again, the language has already made too many sacrifices for "purity of form" for this change to not seem odd, especially considering the existence of alternative like BOOST_FOREACH. Going back to my constructor example, there's no known code, template or macro madness that can fix or even alleviate the redundancy of constructor declaration yet they didn't bother to update that... Obviously "purity of form" means something to the *committee...
 
  • #33
D H said:
How? The old syntax for for loops still works. for is now overloaded. If you don't like the new syntax, don't use it.
I didn't say it broke old code. C++0x was carefully design not to. I'm saying it's breaking old values of C++, like not enforcing a particular convention...

Where? I don't get your objection.
I'm not sure to what you're referring with the word "where."

It's very unlike C++ to enforce certain identifier names to be used with built-in language constructs like for loops...

It's hard to come up with an analogy that demonstrates how weird this is but it's a little like having while loops being able to do naked object evaluations as long as they provide a "do_while" method that returns a boolean, like so:
Code:
class Foo {
    bool do_while() { return true; }  // infinite loop...
};

int main() {
    Foo foo;
    while (foo) {
        // should probably do something...
    }
}
Wouldn't it be weird if C++ started doing things like this?
 
  • #34
Is it worth it to keep with conventions if they limit the convenience of using the language? Consistency is impossible in a complete language.
 
  • #35
D H said:
Jocko Homo said:
I am very curious to know how on God's green Earth it could "appear" as if I'm talking about the auto keyword. Can you please explain this to me?
Because it didn't look like you were talking about the for keyword. I still don't understand your objection.
That doesn't answer my question... at all...

Obviously it didn't appear to you that I was talking about for loops. I asked how didn't it appear so? What did I specifically say that made you rule out the possibility that I was talking about for loops and rule in the possibility that I was talking about auto? I'm baffled by this and I'm curious to see the train of logic...

The entirety of C++ libraries are implemented using the preprocessor? Where did you get that idea? Most of the C++ library is in the form of templates. The preprocessor doesn't know beans about templates.
You had to use the preprocessor to use template libraries in your code with the use of the include directive, which is basically just one giant macro. If you happen to have a text file named "include_me.idontcare" and it contained this:
Code:
for (i = 0; i < whatever; ++i) {
    printf("%i\n", i);
}
...and you compiled this code:
Code:
#include <stdio.h>

int main() {
    int i;
    int whatever = 4;

#include "include_me.idontcare"
}
...the compilation will succeed and the executable will run! ...yet we all recognize that this code is terribly Wrong. Why? Because it's a poorly behaved macro... yet the include directive is the underlying mechanism of C++ library implementation. It's the reason we put up with pre-compiled headers and all that jive...

There's no getting around how integral a part of C++ the preprocessor is so its use can't be shunned that badly. All you can do is ask that people write well behaved macros and good programmers try to do just that...
 
<h2>1. What are the new features in C++0x?</h2><p>The new features in C++0x include concepts, lambda expressions, rvalue references, auto type deduction, and static assertions. There are also improvements to the standard library, such as new containers and algorithms.</p><h2>2. How do concepts work in C++0x?</h2><p>Concepts in C++0x allow for template constraints, which ensure that a template argument meets certain requirements. This helps with type safety and allows for more efficient code. Concepts are declared using the <code>requires</code> keyword and can be used to constrain any template parameter, not just types.</p><h2>3. What are lambda expressions in C++0x?</h2><p>Lambda expressions in C++0x are anonymous functions that can be used inline in code. They are declared using the <code>[]</code> syntax and can capture variables from the enclosing scope. Lambda expressions are useful for creating callbacks and can also be used with algorithms from the standard library.</p><h2>4. How do rvalue references work in C++0x?</h2><p>Rvalue references in C++0x allow for the creation of move constructors and move assignment operators, which can significantly improve performance for objects that are expensive to copy. They are declared using the <code>&&</code> syntax and can be used to distinguish between lvalues and rvalues.</p><h2>5. What is auto type deduction in C++0x?</h2><p>Auto type deduction in C++0x allows for the automatic deduction of a variable's type based on its initializer. This can help reduce the amount of code needed and make it easier to work with complex types. It is declared using the <code>auto</code> keyword and can also be combined with type inference using the <code>decltype</code> keyword.</p>

1. What are the new features in C++0x?

The new features in C++0x include concepts, lambda expressions, rvalue references, auto type deduction, and static assertions. There are also improvements to the standard library, such as new containers and algorithms.

2. How do concepts work in C++0x?

Concepts in C++0x allow for template constraints, which ensure that a template argument meets certain requirements. This helps with type safety and allows for more efficient code. Concepts are declared using the requires keyword and can be used to constrain any template parameter, not just types.

3. What are lambda expressions in C++0x?

Lambda expressions in C++0x are anonymous functions that can be used inline in code. They are declared using the [] syntax and can capture variables from the enclosing scope. Lambda expressions are useful for creating callbacks and can also be used with algorithms from the standard library.

4. How do rvalue references work in C++0x?

Rvalue references in C++0x allow for the creation of move constructors and move assignment operators, which can significantly improve performance for objects that are expensive to copy. They are declared using the && syntax and can be used to distinguish between lvalues and rvalues.

5. What is auto type deduction in C++0x?

Auto type deduction in C++0x allows for the automatic deduction of a variable's type based on its initializer. This can help reduce the amount of code needed and make it easier to work with complex types. It is declared using the auto keyword and can also be combined with type inference using the decltype keyword.

Similar threads

Replies
10
Views
905
  • Programming and Computer Science
Replies
5
Views
2K
  • Programming and Computer Science
Replies
20
Views
1K
  • Programming and Computer Science
Replies
5
Views
848
  • Programming and Computer Science
3
Replies
89
Views
4K
  • Programming and Computer Science
Replies
23
Views
1K
  • Programming and Computer Science
3
Replies
89
Views
4K
  • Programming and Computer Science
Replies
5
Views
2K
  • Programming and Computer Science
Replies
3
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
2
Views
2K
Back
Top