C++0x

A place to discuss the implementation and style of computer programs.

Moderators: phlip, Moderators General, Prelates

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

C++0x

Postby Yakk » Tue Apr 24, 2007 6:02 pm UTC

The process to start work on C++0x has started.

There are some juicy, neat new concepts.

Modules
Module-based import/export of interfaces. This is intended to augment and replace the #include preprocessor command. Users of other languages should be aware of the technique.

The C++ module system will have "partitions" that are analagous to header files, to ease transition. So a module can be broken up into multiple chunks that depend upon one another.

One huge advantage of modules is an expected speedup when compiling large projects, because one doesn't have to recompile the interface of every project in every source-file. There are also significant optimization advantages, because the compiler can decorate the module interface with metainformation about the implementation of functions.

Syntax might look like:

Code: Select all

export ExampleLib {
  private:
    int x = 2;
  public:
    int getx() { return x; }
};

The variable x won't be visible outside of the library. The function getx() will be, because it is public.

There are lots of complex details and gotchas, but that is the core of it. The user would just:

Code: Select all

import ExampleLib;

and they would have access to the ExampleLib public symbols.

Concepts
Concepts are compile-time ducktype contracts. There can be a concept for a "RandomAccessIterator" that is satisfied if an object passes the tests.

This replaces a bunch of ad-hoc hacks in the STL, using traits classes and other mojo. It also simplifies template compiler errors massively. Instead of the error happening at the moment where the ducktyping fails, you instead get an error at the moment the ducktype contract fails.

Similarly, templates can check themselves against their ducktype contract without having to be instantiated.

Google video talk about concepts: (recorded at google)
http://video.google.com/videoplay?docid ... 1047186825
(1 hour long)

They are designed to make "advanced template programming" easy, just as powerful, and capable of very strong results.

(note "where" keyword has since been changed to "requires", and "&&" changed to ",". I think "||" has been discarded.)

constexpr functions and values
Functions and variables that assert they can be evaluated at compile-time. This replaces some of the last decent uses of C-style preprocessor macros. Included are constexpr constructors, which allow you to create compile-time literal user-defined constants.

Compile-time values already have uses. Part of the benefit is being able to tell the compiler "I intend this value to be compile-time determined", and the compiler can complain if you screw up.

rvalue references
The main use of rvalue references is to permit the creation of "move operators" and other similar optimizations. So when your function returns a std::vector, it can be done is O(1) time by the use of "swap" instead of O(n) time by the use of a copy-constructor.

decltype
This allows the user to get the type of an expression. Quite useful if you want to write a wrapper that forwards to another function.

There are other uses, but that is the tastiest one.

Variadic Templates
VarArgs for templates. Type-checking and type-safe printfs, template-based tuples that are not monsters of code generation, and dozens of other uses. This is all done at compile-time, but it resembles the python varargs run-time implementation: you can take a packet of arguements, unpack it, and pass it to a function.

Look at the hacks required by boost::tuple to see the beauty that Variadic tamplates are useful, or a safe printf!

for loop extension: foreach in C++

Code: Select all

for(int i: container) {
  // code
}


automatically iterate over the container without having to manually do the loop. Basically, a foreach. Any object can either match the requirements of the For concept, or they can specialize the For concept for their object.

How about looping over pairs of iterators?

Code: Select all

template<InputIterator Iter>
concept_map For<pair<Iter, Iter> > {
  typedef Iter iterator;
  iterator begin(pair<Iter, Iter> p) { return p.first; }
  iterator end(pair<Iter, Iter> p) { return p.second; }
}

Done!

...

There is a relatively functional C++ reference compiler over here:
http://conceptgcc.wordpress.com/tag/c/

User avatar
kibiz0r
Posts: 11
Joined: Tue Apr 24, 2007 7:42 pm UTC
Location: In your base, killing your mans
Contact:

Postby kibiz0r » Tue Apr 24, 2007 7:52 pm UTC

I'm very excited about C++0x, but you missed the best part: effortless multithreading. Really big deal since, these days, raw speed is yielding to more cores.

Ripped from Wiki, because I'm lazy.

Parallel execution

Although the proposal still has to be defined, a mechanism to create the construction cobegin and coend using threads is likely to be introduced in the next standard (or in the future).

For the time being, the keyword used for the new notation is not important. Instead, it is important to know how simple it will be to implement parallel executable instruction blocks.

Code: Select all

active
{
  // First block.
  {
    // ...
  }
  // Second block.
  for( int j = N ; j > 0 ; j-- )
  {
    // ...
  }
  // Third block.
  ret = function(parameter) ;
  // Other blocks.
  // ...
}


All blocks are executed in parallel. After the execution of every block has ended, the program continues with a single thread.

Asynchronous function call

Another undefined proposal that could be introduced in the next standard is a mechanism to implement an asynchronous function-like call using concept of future.

The syntax will probably be similar to following example:

Code: Select all

int function( int parameter ) ;
// Calls the function and immediately returns.
IdThreadType<function> IdThread = future function(parameter) ;
// Waits for the function result.
int ret = wait IdThread ;


Thread-local storage

In a multi-threaded environment, every thread must often have unique variables. This already happens for the local variables of a function, but it does not happen for global and static variables.

A new local storage in addition to the numerous existing ones (extern, static, register, auto and mutable) has been proposed for the next standard: the Thread-Local Storage. This new local storage should be called simply thread (at the moment in the official documentation it uses the name __thread).

A thread object is similar to a global object. Global objects have a scope that covers all the program execution, while thread objects have a scope limited to a single thread. At the end of thread execution the thread objects are rendered inaccessible. Like any other static-duration variable, a thread object can be initialized using a constructor and destroyed using a destructor.

Atomic operations

Often, a thread needs to perform a task without being interrupted. For example, a thread might require exclusive access to a global variable or real-time access to a peripheral.

To perform such an atomic operation, a new keyword atomic has been proposed:

Code: Select all

atomic
{
  // Atomic operations.
  ...
}


A new meaning for the volatile modifier

Currently, the modifier volatile informs the compiler that a variable’s value can be modified at any moment. In other words, accesses and modifications to a variable with this modifier must go directly to the variable's location in memory, and cannot take advantage of temporary storage in a CPU register. Furthermore, compilers cannot strip seemingly redundant assignments to volatile variables as this modifier signals that other code segments may attempt to read the variable's value concurrently. In the absence of the volatile keyword, compilers assume that a variable will maintain its value unless it receives an assignment in the current scope, allowing the generally desireable optimization known as dead code elimination.


A proposal for C++0x includes using the volatile keyword for communication between threads. Under this proposal, the compiler would guarantee thread-safety for concurrent reading and writing of volatile objects. This would, in effect, cause compilers to emit thread-synchronization code for accessing/modifying so-modified objects. However, this solution appears inappropriate if applied to complex object and its use is still in discussion.
This post has been modified from its original version. It has been formatted to fit your mind.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Postby EvanED » Tue Apr 24, 2007 7:53 pm UTC

There are also likely some things (my impression is that they were looking really likely to be standardized a couple years ago, though I don't know the formal state) that could qualify as syntactic sugar in some form or another:

Template typedefs:

Code: Select all

template <typename T>  typedef strmap map<string, T>

would create a new template type, strmap<T>, that would be a map from strings to Ts.

Better >> parsing in templates:

Code: Select all

vector<vector<int>>

will parse "correctly", instead of the >> being interpreted as a right shift

auto keword overloaded:
You can declare a variable as "auto x = ..." and it will insert the type to be equal to the right side. This means you can write:

Code: Select all

for(auto iter = v.begin() ; iter != v.end() ; ++iter)

instead of

Code: Select all

for(vector<string>::iterator iter = v.begin() ; iter != v.end() ; ++iter)


Hmm, that's what I can think of off the top of my head. There are also a number of important library improvements introduced in TR1, and more on the way; hash tables, reference-counted smart pointers, regular expressions (all in TR1), sockets, maybe threads, containers that you can inherit from "properly", etc.

Then syntactic sugar for libraries: better use of std::string (fstream::open requires a char*? WTF?!), the ability to initialize containers from literals (vector<int> v = {0,1,2}), the ability to call algorithms that usually take iterator pairs with a container instead (sort(v) instead of sort(v.begin(), v.end())), and some others.


The main use of rvalue references is to permit the creation of "move operators" and other similar optimizations. So when your function returns a std::vector, it can be done is O(1) time by the use of "swap" instead of O(n) time by the use of a copy-constructor.


Oh, that's beautiful.

User avatar
kibiz0r
Posts: 11
Joined: Tue Apr 24, 2007 7:42 pm UTC
Location: In your base, killing your mans
Contact:

Postby kibiz0r » Tue Apr 24, 2007 8:02 pm UTC

It's probably worth noting that you can get a lot of the handy C++0x functionality from boost already.

You don't get any of the core language features, but you get smart_ptrs, STL arrays, and a zillion other useful tidbits that are presumably being incorporated into C++0x.
This post has been modified from its original version. It has been formatted to fit your mind.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Postby EvanED » Tue Apr 24, 2007 8:05 pm UTC

kibiz0r wrote:It's probably worth noting that you can get a lot of the handy C++0x functionality from boost already.

You don't get any of the core language features, but you get smart_ptrs, STL arrays, and a zillion other useful tidbits that are presumably being incorporated into C++0x.


Yes. That applies more to my post than Yakk's, as Yakk didn't really touch on the library stuff.

TR1 added 14 libraries to C++; IIRC, 10 were based heavily on Boost's implementation.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Postby EvanED » Tue Apr 24, 2007 8:16 pm UTC

kibiz0r wrote:I'm very excited about C++0x, but you missed the best part: effortless multithreading. Really big deal since, these days, raw speed is yielding to more cores.


<programming philosophy> Multithreading will never be effortless, at least not for many decades. I think there's a good chance strong AI will come first. </programming philosophy>

Asynchronous function call

Another undefined proposal that could be introduced in the next standard is a mechanism to implement an asynchronous function-like call using concept of future.

The syntax will probably be similar to following example:

Code: Select all

int function( int parameter ) ;
// Calls the function and immediately returns.
IdThreadType<function> IdThread = future function(parameter) ;
// Waits for the function result.
int ret = wait IdThread ;


If you add threads to the language, I don't think that this needs to be done as a language feature; there will probably be no "future" or "wait" keyword for instance.

This would, in effect, cause compilers to emit thread-synchronization code for accessing/modifying so-modified objects. However, this solution appears inappropriate if applied to complex object and its use is still in discussion.


Hmm, I'm not sure that that solution appears appropriate if applied to primitive objects.


Looking through the Wikipedia page, other things that I find useful:
opaque typedefs:
With some other syntax, "typedef int month" would define a new type month that wasn't implicitly convertible to or from ints. D calls this "strong typedefs", and it's something I've wanted for some time.

Currently you have to hack this together with templates and macros; e.g. write "STRONG_TYPEDEF(int, month)" and hope the compiler gives you good code.

nullptr:
I forgot about this, but this is actually more important than it appears. Assume you have

Code: Select all

int foo( char* );
int foo( int );

and then you call "foo(NULL)". What happens? Well, NULL expands to 0, which is an int, so it calls foo(int). C++0x adds the nullptr keyword, which is a literal null value.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Postby Yakk » Tue Apr 24, 2007 10:23 pm UTC

The problem is, that thread stuff looks meh.

|| blocks isn't bad, so long as there is a decent way to create cheap || block harnesses.

Futures look like something that should be built out of more-primitive syncronization objects. Do they plan on allowing Future<int>+5 to work, producing a Future<> of the appropriate type?

Such "syntax tree" building seem like a feature that would be more useful than the raw idea of Future's.

Atomic looks horrible. Efficiently doing multiple-instruction atomic operations are ridiculously expensive, and quite prone to deadlocks.

I suppose the problem is we aren't all that good at multithreaded programming, so folding it into the language has issues.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: C++0x

Postby Yakk » Wed Feb 20, 2008 2:02 am UTC

Another year, and lots of work on C++0x.

Latest working group: (Feb 8th, 2008)
http://www.open-std.org/jtc1/sc22/wg21/ ... n2507.html
it contains multiple levels of current papers, which will give you a good idea about how likely each proposal is to get into the Cx09 standard. There is so much to drool over!

Here is the latest working paper:
http://www.open-std.org/jtc1/sc22/wg21/ ... /n2461.pdf
(Oct 2007)

I find this part funny:
No interest, or superseded by other proposals
These papers have either been superseded by different set of proposals, or were identified as a something we do not want to do. While everyone is free to submit papers they feel strongly about, it is unlikely any of these topics will gain favour for a future standard unless something significantly new is presented with the updated paper.

italics mine. :)

...

Another lovely bit:
http://www.open-std.org/jtc1/sc22/wg21/ ... /n2442.htm
"This proposal unifies the changed wording to avoid race conditions in editing the text."

GEEKS!
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

coppro
Posts: 117
Joined: Mon Feb 04, 2008 6:04 am UTC

Re: C++0x

Postby coppro » Wed Feb 20, 2008 5:20 am UTC

That's not the latest working paper!

n2521 is!

Some of my favorite things so far:

Concepts (not in the working draft). Concepts are looking to be one of the most powerful elements of C++. For instance, you can have member functions that only exist if a certain requirement is met.
Basically, they take all that was good about template metaprogramming and made a language of it.

Threading library (in the working draft). It's looking good as far as a basic library goes. It'll be nice to finally be able to code threads in C++ - though it may be difficult to learn this library (I don't fully understand it yet myself).


The following things haven't really been covered yet, so I'll go into a bit more detail.

Lambdas (not in the working draft). Another great feature that makes using the STL almost like coding in Lisp. Almost. But C++ is quickly becoming the Perl of compiled languages. :roll: These are undergoing some final wordcrafting, but a lambda in its most simple form might look like "<>(int x, int y)(x + y)", which is a lambda functor that returns the sum of two integers. If the code is only one statement, it can be encompassed in the parentheses, like the example. You can use a block, but then you have to explicitly specify the return type "<>(int x, int y) -> int {int z = x + y; if (z % 2) ++z; return z;}". There will also be ways to inherit variables from the local scope (either by value or reference - the latter could create a dangling reference, while the former can be used to create a true closure). The variables can be inherited either all at once, or individually.

Also, you can store a lambda via use of the 'auto' declarator. Unfortunately, they can only be passed to template functions (although they can always be wrapped in the appropriate STL functors), because each lambda has a distinct type.

Initializer syntax (not in the working draft). This is a really cool one. Remember the struct initializations in C done with {}? Well, they're back with a vengeance. It's too detailed to describe here, but basically, you can use {} just about anywhere. Besides meaning that you can now specify arrays on the fly with {}, you can also make classes that take a new std::initializer_list<T> type, that basically stores an array of {}s in a safe method. If there isn't a match, the contents of the {} can also be used as parameters for the contructor - and these declarations can go anywhere. This is an awesome, awesome feature.


Other things mentioned here have been taken out - an atomic keyword/changing volatile have been discarded in favor of making use of a set of atomic structures in the library - atomic_int, atomic_char32_t, etc. as well as a template that can be used for atomic storing/loading of any sort of variable - though it requires use of the copy constructor. A lot of other threading components have undergone significant review. Modules are being deferred from this standard - perhaps next time, I guess. Opaque/strong typedefs seem to have disappeared, and the template typedef syntax has been changed to "template <typename T> using strmap = map<string, T>", which is otherwise the same as EvanED's example. {EDIT: The above statement is incorrect. Templated typedefs are now allowed - the using syntax is just another way to introduce a typedef}
Last edited by coppro on Thu Feb 21, 2008 5:51 am UTC, edited 1 time in total.

HappySmileMan
Posts: 52
Joined: Fri Nov 09, 2007 11:46 pm UTC

Re: C++0x

Postby HappySmileMan » Wed Feb 20, 2008 10:12 pm UTC

I understand and would find useful Modules, Active (The threading thing) and constexpr, everything else seems fairly complicated to me, though I am tired.

coppro
Posts: 117
Joined: Mon Feb 04, 2008 6:04 am UTC

Re: C++0x

Postby coppro » Thu Feb 21, 2008 12:02 am UTC

HappySmileMan wrote:I understand and would find useful Modules, Active (The threading thing) and constexpr, everything else seems fairly complicated to me, though I am tired.
Unfortunately, Modules are now out. Threading is looking more like a typical POSIX library (read: hard to use).

The new use of the auto keyword is something you'll definitely appreciate, though, if you ever tried to iterate through a vector.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: C++0x

Postby Yakk » Thu Feb 21, 2008 3:42 am UTC

A "quick" read over of the last meeting gives me the following new features:

C++09

This was formally known as C++0x. It is the next iteration of the C++ programming language.

***

Rvalue Reference (can only hold temporary values).
Among other things, this gives us move semantics!

***

static_assert (asserts that are checked at compile time).

***

New typedef like syntax (aliases):
using type_name = definition;
and
template<typename X> typename = definition;
allowing template aliases.

***

extern template, which gives us the ability to move templates out of header files.

***

Variadic Templates: templates with a variable number of arguments.

So you can have a tuple<a, b, c, d, e, f, ...> type that doesn't require a wall of generated code.

This also allows a type-safe and type-checked printf command.

***

nullptr: this is a NULL value that isn't the same as the value 0. nullptr cannot be implicitly cast to an int, which is very useful when you override a function to take either an int or a pointer. :)

***

strongly typed enums, called "enum class".

You can tell enums not to casually turn into integers.
You can also specify the underlying type. (currently, any structure containing an enum could have it's size change at the wim of the compiler version -- this is _bad_)

ie:
enum class E : unsigned long { E1=1, E2=0xFFFFFFF };
(default type is int)

In addition
enum test: unsigned long {A=1, B, C};
will work (so youc an take an existing enum, and specify it's underlying type).
_and_, test::A will be legal.

***

Some touchups to the friend keyword -- mainly better lookup for the friend target.

***

constant expressions.

These are functions that can be evaluated at compile time, and then used at compile time for compile-time only values, like the size of arrays.

This allows you to make functions that are guaranteed to act like macros and be evaluated at compile time into a constant value, if the inputs are also constant expressions.

***

Alignment support: if 4k aligned memory sounds useful, this will provide it.

***

Conditionally supported extensions. When they add new things to the standard that are "optional", instead of undefined behavior a compiler must say "I don't support this". Filesystem support in the standard library was mentioned as one candidate for this. asm directives are another example.

***

long long, 64 bit native C++ type.

This also means that values near 2^32 will change from unsigned to signed types, which in a few cases might cause problems.

(In C++03/C89, (1<<31)>-1 is false. In C99/C++09, it will be true.)

***

Delegating constructors

class X {
int i;
public:
X(int i_): i(i_) {}
X(): X(42) {};
};

'nuff said

***

Unicode support: ISO 19769:2004, but fixed to work in C++

E"blah" -- UTF-8
u"blah" -- 16 bit unicode, in char16_t
U"blah" -- 32 bit unicode, in char32_t
And a whole host of functions to work on unicode data.

Some changes to backslash character expressions.

***

Raw string literals
For regular expresions and raw XML/HTML.
R"[foo""\]" contains nothing except foo""\
Removes leaning toothpick syndrom
Trigraphs, UCN and backslash-newlines are still converted.

***

auto typed data.

int foo();
auto x = foo(); // x is automatically of type int.

This is very useful for complex types, such as generated by some template functions.

***

Improvements to the inanity of PODs.

***

Explicit default constructors
class X{ X()=default; };

***

Rethrowing exceptions between thread support

***

decltype -- you can get the type of an expression, and then use it.

ie, decltype(1+1) x;, or decltype(foo(bar)) y;

sort of like sizeof, but is "typeof".

***

sizeof improvements: sizeof(class::member) works for non-static members

***

Tweaks to the sequence point rules. Scary, but confusing!

***

Explicit conversion operators (so your bool-convertable smart pointer only converts when asked)

***

Concurrancy model, and threading and atomic support in-language

***

__func__ preprocessor macro, that contains the name of the current function (yay)

***

quick_exit and at_quick_exit

intended for multithreaded programs where winding down every thread isn't practical, this allows an application to shut down semi-cleanly while threads are still running, and not require static destructors to be universally called.

***

function=default;
and
function=delete;

let you explicitly start using the "default" version of a function (useful for operator=, copy constructors, etc), or remove a function from scope explicitly;

***

The above are all "ready to be added to standard" or "in standard". Below are less developed:

initializer lists: Ie,
std::vector<int> foo = {1,2,3,10,-1};
and
foo[{1,2,4}] = 7; // !

***

concepts: this is a serious feature.

It means the end of template-spagetti errors.
It means lots of things enforced by documentation, like the layout of iterators, are made explicit.
It lets you tell the compiler "my object can be iterated over. Here is how to do it", and other people to access this concept and use it.

Basically, it changes templates from powerful arcane magic to a powerful tool. :)

***

strong namespace inclusion. A technical trick, really, that makes using namespace do what you want it to do (but you use extern using namespace) in many cases.

Very useful inside the standard library apparently.

***

inheriting constructors from your parents.

So you can inherit from std::vector, and change some behavior, but not have to rewrite or explicitly forward the constructors.

***

class member initializers

class A {
int member = 7;
};

tasty.

***

range-based for loops:

std::vector<int> my_vec;
fill_vector(my_vec);
for(int& i: vec) {
i *= 2;
}

And you can, using concept maps, have your own containers work. This doesn't require that you rewrite your class to inherit from some common interface, either.

You just give the compiler instructions on how to iterate over your container using the Range concept_map, and viola, range-based for loops work on your class.

***

Being able to pass local classes, and a few other things, to templates! So good.

***

User-defined literals.
123km creates something of type determined by the suffix, km.
Similarly, "Hello!"s is a std::string containing "Hello!".

"Hello!"s calls operator"s"(...)

You can get both 'raw' and 'cooked' data. The raw is (basically) the string of the literal, allowing arbitrary precision integer literals and other useful things.

This can be done at compile-time for raw, run-time for raw (simpler), or run-time for cooked (maybe compile-time for some cooked?).

***

thread_local, for thread local storage data.

***

Lambda functions.
<>(int x, int y)(x+y) // function that adds 2 ints. Return type auto-deduced
<>(int x, int y)->int (x+y) // with explicit return type
<>(int x, int y)->int {int z=x+y; return z;} // with a block body
<>(int y):[x] (x+y) // gets the value of x from the local scope
<>(int y):[&total](total+=y) // gets total by reference from local scope
<=>(int y) (x+y) // <=> means get the local scope variables by-copy if needed
<&>(int y) (total+=y) // <&> means the entire scope is imported by reference

Note that lambda functions each have a unique, anonymous type. You can store them in the new function objects that are coming with C++09, however.

***

attributes -- standard things like __declspec.

Syntax:
class C [[contents_attribute]] { /* contents */ } [[class_type_attribute]] c [[instance_attribute]];

and similar syntaxes for control flow, such as
if [[probably(true)]] (i == 42) {...}

another example:
char*[[owner]] strdup( char*[[not_owner]]);
which states that you get a char* that you own, and you pass in a char* that the function does not own.

(note [[]] vs something like attribute(()) isn't decided).

***

unions can contain anything now. Use at own risk.


Any errors? Important omissions?
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

coppro
Posts: 117
Joined: Mon Feb 04, 2008 6:04 am UTC

Re: C++0x

Postby coppro » Thu Feb 21, 2008 5:59 am UTC

Yakk wrote:function=default;
and
function=delete;

let you explicitly start using the "default" version of a function (useful for operator=, copy constructors, etc), or remove a function from scope explicitly;
Not quite... "delete" actually declares a function, but with a nonexistant implementation. So it's an error to call a deleted function, but this is useful in other situations like where you might want a function that takes an int, but not a float. You can declare an overload that takes a float as deleted, and the compiler can flag any calls without casted floats as errors (explicit parameters might be easier, but it could also be used for other purposes, or for removal of a deprecated function (because then the programmer at least knows that someone went to the trouble as declaring the prototype as deleted, rather than removing it entirely)).

Also, I'll write a big post on the subject of concepts - it's worth a whole post or two to explain. Once most programmers understand them, the only question left to ask will be "why can't this be done at runtime? That would make C++ perfect!"

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: C++0x

Postby EvanED » Thu Feb 21, 2008 6:39 am UTC

If you've got a spare hour, this video explains concepts pretty well.

coppro
Posts: 117
Joined: Mon Feb 04, 2008 6:04 am UTC

Re: C++0x

Postby coppro » Thu Feb 21, 2008 8:13 am UTC

EvanED wrote:If you've got a spare hour, this video explains concepts pretty well.
That's very good, and I would highly recommend it, but it's outdated, or left some things out (I don't know the history of concepts, though I've read the entire current proposed wording). The current revision has the following improvements:

Requirements:

Now we use the 'requires' keyword instead of 'where'. To specify multiple requirements, you use the && operator. There is no || operator - you just use a specialization/overload instead.

You can also conditionally specify or overload template member functions based on a concept requirement - essentially performing an implicit specialization of your class to include the extra member.

You can also specify in a concept that a constructor or conversion operator be explicit - non-explicit requirements never match explicit constructors/conversions.

Lastly, you can impose lvalue and rvalue reference requirements on member functions, just like you can impose a requirement of a const member function.

Automatic instantiation:

An important new/omitted feature is automatic instantiation. The compiler can guess various required aspects - for instance, if it requires an == operator, you don't need to explicitly map it if your class already contains a matching operator. The compiler can deduce non-member functions like this, but not type names - these can be deduced from function return types, or they can be explicitly specified. Default implementations/types are always the compiler's last resort - chosen if and only if this instantiation fails.

You can also use the 'auto' specifier on a concept, which essentially adds an empty concept map for every type - so that any type that implicitly matches can be considered to meet the concept, without a specified map for each type.

late_check:

A new block construct called late_check has been added, which forces a constrained template to act unconstrained, so it follows the regular two-stage name lookup rules, rather than the compartementalized concept system.

Simple form of multiple-parameter concepts:

Just as you can write

Code: Select all

template <InputIterator I>
rather than

Code: Select all

template <typename T> requires InputIterator<T>
, you can use auto to achieve a similar effect with multiple paramters, with a construct like

Code: Select all

template <typename T, BinaryPredicate <auto, T> Pred>
as opposed to

Code: Select all

template <typename T, typename Pred> requires BinaryPredicate<Pred, T>
.

Standard concepts:

Many type traits are now being expressed as standard concepts, so it's easy to overload/specialize a template based on whether or not a class meets a certain type trait requirement. There's also a True<boolean> concept, for use with non-concepted template predicates. There are a number of other integrated concepts - for instance, declaring a type to be returned from a function implicitly adds a Returnable requirement on that type (which is by default any type that's MoveConstrutible or is void) - allows the compiler to add even better checking mechanisms = particularly useful in templates where you can get bizarre constructs like references to references.

Lastly:

A last interesting tidbit: it's much easier to write a compiler for constrained (with concept) templates rather than non-constrained ones, because of two-phase name lookup (particulary WRT export).

MPL, eat your heart out.

Ambeco
Posts: 105
Joined: Thu Mar 03, 2011 12:17 am UTC

Re: C++0x

Postby Ambeco » Tue Apr 26, 2011 6:27 pm UTC

I was thinking about constexpr.
1) Is there a reason constexpr can't have local variables so long as it still matches all the other limitations (basically not accessing anything non-constexpr)? This seems like a arbitrary limitation that hinders for no reason.
2) It seems like the compiler should do this automatically for any function that matches the prerequisites, or else someone is going to have to add constexpr to large portions of the standard libraries. (tuple, cmath, char_traits, numeric_limits, ...)
3) Can we finally use this somehow to use a member of a constexpr array (who's size is known at compile-time) as a compile-time constant? EG:

Code: Select all

template<int len, constexpr char tstr[len]>
Type { enum letters{first=tstr[0] /*can't do this*/}; };
constexpr char LetterA = Type<6,"APPLE">::first;
where it's in bounds of course, otherwise it'd be ill-formed.
Since I've heard of C++0x, I've wanted printf<"HI %s">(...) to know that it took one char* pointer, and thus be able to do automatic type promotion/type safetly. Right now the only way to do this is a patch that someone made against gcc revision 134411, which expands string literals into a template argument pack of characters (and is known to be buggy) here: http://objectmix.com/c/377452-string-li ... ge_1412252.

User avatar
Yakk
Poster with most posts but no title.
Posts: 11129
Joined: Sat Jan 27, 2007 7:27 pm UTC
Location: E pur si muove

Re: C++0x

Postby Yakk » Tue Apr 26, 2011 7:09 pm UTC

Ambeco wrote:I was thinking about constexpr.

So the thing to realize about constexpr is that the C++0x standard is bending over backwards to make it easy to implement.

In particular, much of what constexpr did was already done by many compilers for the purpose of optimization. Rather than stretching things to the point where it was logically possible, instead they took a look at what already existing compilers tended to do, and codified it, and added the formal ability to treat it as a compile-time expression.
1) Is there a reason constexpr can't have local variables so long as it still matches all the other limitations (basically not accessing anything non-constexpr)? This seems like a arbitrary limitation that hinders for no reason.

See above. Probably common implementations didn't handle having local variables, so they didn't throw that in.

The goal was to be "good enough and shipping" rather than "ideal and nobody implements it".
2) It seems like the compiler should do this automatically for any function that matches the prerequisites, or else someone is going to have to add constexpr to large portions of the standard libraries. (tuple, cmath, char_traits, numeric_limits, ...)

No. While the compiler automatically detecting this stuff is sometimes useful, being able to say "I want this to be a constexpr" means that the compiler can express errors at the point where the constexpr-ness of the function fails, instead of at the point of use.

By saying "this is a constexpr", it describes a very important part of how that function can be used. So users of the function can use it without having to analyze "is this constexpr?" -- and writers of the function can write it and get errors at point of writing without having to throw in test cases to "assert I'm constexpr".

In addition, what you describe is fragile. I use a function that isn't intended to be constexpr as a constexpr. Someone changes an implementation detail, and all of a sudden my code breaks.
One of the painful things about our time is that those who feel certainty are stupid, and those with any imagination and understanding are filled with doubt and indecision - BR

Last edited by JHVH on Fri Oct 23, 4004 BCE 6:17 pm, edited 6 times in total.

Ambeco
Posts: 105
Joined: Thu Mar 03, 2011 12:17 am UTC

Re: C++0x

Postby Ambeco » Tue Apr 26, 2011 11:55 pm UTC

Wow, that's a very clear and informative answer. That totally clears up my questions.

EvanED
Posts: 4331
Joined: Mon Aug 07, 2006 6:28 am UTC
Location: Madison, WI
Contact:

Re: C++0x

Postby EvanED » Wed Apr 27, 2011 12:59 am UTC

BTW, the comments about one of the disadvantages of inferring 'constexpr' being that it's hard to predict reminds me a bit of languages with Hindley-Milner type inference. Sure, the languages can do a lot of heavy lifting for you, but if you talk to a lot of people who use these languages, they include type annotations for a lot of their functions anyway. It makes (compile-time) debugging easier because the compiler can't infer something that you don't expect that leads to a type error somewhere else.


Return to “Coding”

Who is online

Users browsing this forum: No registered users and 9 guests