tags:

views:

1218

answers:

8

C++0x will introduce user-defined literals which will allow the introduction of new literal syntax based on existing literals (int, hex, string, float) so that any type will be able to have a literal presentation.

Examples:

// imaginary numbers
std::complex<double> operator "i"(double d) // cooked form
{ 
    return std::complex<double>(0, d); 
}
auto val = 3.14i; // val = complex<double>(0, 3.14)

// binary values
int operator "B"(const char*); // raw form
int answer = 101010B; // answer = 42

// std::string
std::string operator "s"(const char* str) { return std::string(str); }
auto hi = "hello"s + " world"; // + works, "hello"s is a string not a pointer

// units
assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

At first glance this looks very cool but I'm wondering how applicable it really is, when I tried to think of having the suffixes AD and BC create dates I found that it's problematic due to operator order. 1974/01/06AD would first evaluate 1974/01 (as plain ints) and only later the 06AD (to say nothing of August and September having to be written without the 0 for octal reasons). This can be worked around by having the syntax be 1974-1/6AD so that the operator evaluation order works but it's clunky.

So what my question boils down to is this, do you feel this feature will justify itself? What other literals would you like to define that will make your C++ code more readable?

+1  A: 

I have never needed or wanted this feature (but this could be the Blub effect). My knee jerk reaction is that it's lame, and likely to appeal to the same people who think that it's cool to overload operator+ for any operation which could remotely be construed as adding.

fizzer
nice essay about the blub effect btw.. I had a good read.
Nils Pipenbrinck
I confirm: Very interesting article.
paercebal
+6  A: 

It's very nice for mathematical code. Out of my mind I can see the use for the following operators:

deg for degrees. That makes writing absolute angles much more intuitive.

double operator "deg"(double d)
{ 
    // returns radians
    return d*M_PI/180; 
}

It can also be used for various fixed point representations (which are still in use in the field of DSP and graphics).

int operator "fix"(double d)
{ 
    // returns d as a 1.15.16 fixed point number
    return (int)(d*65536.0f); 
}

These look like nice examples how to use it. They help to make constants in code more readable. It's another tool to make code unreadable as well, but we already have so much tools abuse that one more does not hurt much.

Nils Pipenbrinck
+2  A: 

Hmm... I have not thought about this feature yet. Your sample was well thought out and is certainly interesting. C++ is very powerful as it is now, but unfortunately the syntax used in pieces of code you read is at times overly complex. Readability is, if not all, then at least much. And such a feature would be geared for more readability. If I take your last example

assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

... I wonder how you'd express that today. You'd have a KG and a LB class and you'd compare implicit objects:

assert(KG(1.0f) == LB(2.2f));

And that would do as well. With types that have longer names or types that you have no hopes of having such a nice constructor for sans writing an adapter, it might be a nice addition for on-the-fly implicit object creation and initialization. On the other hand, you can already create and initialize objects using methods, too.

But I agree with Nils on mathematics. C and C++ trigonometry functions for example require input in radians. I think in degrees though, so a very short implicit conversion like Nils posted is very nice.

Ultimately, it's going to be syntactic sugar however, but it will have a slight effect on readability. And it will probably be easier to write some expressions too (sin(180.0deg) is easier to write than sin(deg(180.0)). And then there will be people who abuse the concept. But then, language-abusive people should use very restrictive languages rather than something as expressive as C++.

Ah, my post says basically nothing except: it's going to be okay, the impact won't be too big. Let's not worry. :-)

mstrobl
Your parentheses are unbalanced! Sorry, my OCD hates me too.
X-Istence
A: 

Line noise in that thing is huge. Also it's horrible to read.

Let me know, did they reason that new syntax addition with any kind of examples? For instance, do they have couple of programs that already use C++0x?

For me, this part:

auto val = 3.14i

Does not justify this part:

std::complex<double> operator "i"(double d) // cooked form
{ 
    return std::complex(0, d);
}

Not even if you'd use the i-syntax in 1000 other lines as well. If you write, you probably write 10000 lines of something else along that as well. Especially when you will still probably write mostly everywhere this:

std::complex<double> val = 3.14i

'auto' -keyword may be justified though, only perhaps. But lets take just C++, because it's better than C++0x in this aspect.

std::complex<double> val = std::complex(0, 3.14);

It's like.. that simple. Even thought all the std and pointy brackets are just lame if you use it about everywhere. I don't start guessing what syntax there's in C++0x for turning std::complex under complex.

complex = std::complex<double>;

That's perhaps something straightforward, but I don't believe it's that simple in C++0x.

typedef std::complex<double> complex;

complex val = std::complex(0, 3.14);

Perhaps? >:)

Anyway, the point is: writing 3.14i instead of std::complex(0, 3.14); does not save you much time in overall except in few super special cases.

Cheery
You'd write ``auto val = 3.14i``.
Mikael Jansson
What you want for the last part is using std::complex;Then you can do complex val = complex(0, 3.14);I still like auto val = 3.14i; better.
KeithB
@Cheery: For you, "auto val = 3.14i" does not justify the code written to support it. I could answer that, for me "printf("%i", 25)" does not justify the code written for printf. Do you see a pattern?
paercebal
@Cheery: "Line noise in that thing is huge". No, it isn't... "Also it's horrible to read". Your subjective argument is interesting, but you should take a look at operator overloading in general to see the the code for this feature is far from surprising/shocking... For a C++ developer
paercebal
auto will help readability. consider using interators in a for loop: for(auto it = vec.begin();it!=vec.end();++it)... I know about for_each, but dislike having to create a functor to use it.
KitsuneYMG
@kts: With C++1x we'll have lambda and range for
Joe D
+23  A: 
paercebal
Thank you, me and my other alternate personalities have been discovered. More seriously, I did write this alone, but perhaps I am using some my native language's expression and they don't translate well into english.
paercebal
As for the "different parts", as shown by their titles, sorry, I guess this organizes somewhat a quite long post. As for the bold text, it is the summary of the paragraph they are in. People wanting only the info without justification can limit their reading on the titles and bold text.
paercebal
Thanks for the edit paercebal [I removed my comment about the post being a mess ;o) ]
Motti
+1. Really nice explanation. We are waiting for this to be implemented. It is really important for us. We work on MDE (Model-Driven Engineering) and find this a neccesity. I'm adding a response below to explain our case.
Diego Sevilla
+3  A: 

Under the current draft, the syntax is actually slightly different (and it must take long double:

std::complex<long double> operator "" i(long double d)

UDLs are namespaced (and can be imported by using declarations/directives, but you cannot explicitly namespace a literal like 3.14std::i), which means there (hopefully) won't be a ton of clashes.

The fact that they can actually be templated (and constexpr'd) means that you can do some pretty powerful stuff with UDLs. Bigint authors will be really happy, as they can finally have arbitrarily large constants, calculated at compile time (via constexpr or templates).

I'm just sad that we won't see a couple useful literals in the standard (from the looks of it), like s for std::string and i for the imaginary unit.

The amount of coding time that will be saved by UDLs is actually not that high, but the readability will be vastly increased and more and more calculations can be shifted to compile-time for faster execution.

coppro
+1  A: 

C++ is usually very strict about the syntax used - barring the preprocessor there is not much you can use to define a custom syntax/grammar. E.g. we can overload existing operatos, but we cannot define new ones - IMO this is very much in tune with the spirit of C++.

I don't mind some ways for more customized source code - but the point chosen seems very isolated to me, which confuses me most.

Even intended use may make it much harder to read source code: an single letter may have vast-reaching side effects that in no way can be identified from the context. With symmetry to u, l and f, most developers will choose single letters.

This may also turn scoping into a problem, using single letters in global namespace will probably be considered bad practice, and the tools that are supposed mixing libraries easier (namespaces and descriptive identifiers) will probably defeat its purpose.

I see some merit in combination with "auto", also in combination with a unit library like boost units, but not enough to merit this adition.

I wonder, however, what clever ideas we come up with.

peterchen
+1  A: 

Let me add a little bit of context. For our work, user defined literals is much needed. We work on MDE (Model-Driven Engineering). We want to define models and metamodels in C++. We actually implemented a mapping from Ecore to C++ (EMF4CPP).

The problem comes when being able to define model elements as classes in C++. We are taking the approach of transforming the metamodel (Ecore) to templates with arguments. Arguments of the template are the structural characteristics of types and classes. For example, a class with two int attributes would be something like:

typedef ::ecore::Class< Attribute<int>, Attribute<int> > MyClass;

Hoever, it turns out that every element in a model or metamodel, usually has a name. We would like to write:

typedef ::ecore::Class< "MyClass", Attribute< "x", int>, Attribute<"y", int> > MyClass;

BUT, C++, nor C++0x don't allow this, as strings are prohibited as arguments to templates. You can write the name char by char, but this is admitedly a mess. With proper user-defined literals, we could write something similar. Say we use "_n" to identify model element names (I don't use the exact syntax, just to make an idea):

typedef ::ecore::Class< MyClass_n, Attribute< x_n, int>, Attribute<y_n, int> > MyClass;

Finally, having those definitions as templates helps us a lot to design algorithms for traversing the model elements, model transformations, etc. that are really efficient, because type information, identification, transformations, etc. are determined by the compiler at compile time.

Diego Sevilla