Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: C++ standards  (Read 114009 times)

0 Members and 2 Guests are viewing this topic.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
C++ standards
« on: February 22, 2017, 05:09:38 pm »
Info & Rules about this sub-forum

SFML 2.x is currently stuck with C++03 and it's starting to show in various places. For SFML 3 we had decided already quite a while ago, that we will be using C++11. In the meantime however, C++14 has become widely spread and most compilers out there support all or all important features of the C++14 standard. While SFML 3 is in development for the next x months, one might even ask yourself, whether C++17 might an option.

In this discussion, we want to focus on what features of the new C++ standards SFML can make use of and how these language features should be applied. However, this discussion is not about whether standard classes such as std::thread/std::chrono should replace the SFML's equivalents; those will be discussed separately.

Here are some points that might aid as foundation for the discussion.
  • C++11, C++14, C++17?
  • Move semantics for resource classes
  • Remove component-wise overloads in favor of initializer lists: setPosition(x,y) -> setPosition({x,y})
  • Code simplification: smart pointers, type inference, range-based for, delegating/inheriting constructors, nullptr, lambda expressions, std::function, std::tuple
  • [[deprecated]] attribute (C++14)

Let's start things off with a recently written list of questions by binary1248.

Quote from: binary1248
  • When/Where do we use initializer lists? Everywhere possible, or only in certain scenarios?
  • Uniform initialization? {} everywhere or () as it was in C++03?
  • Almost always auto? Or are there cases when auto is not desired?
  • When do we start using decltype instead of having to type out something that can't be auto deduced?
  • Do we use generic lambdas (C++14)? Or C++11 non-generic lambdas?
  • How do we format lambdas?
  • Do we rather specify the lambda return type or static_cast a return value that causes ambiguity?
  • I assume we make use of override everywhere where it makes sense?
  • When do we use nullptr? Everywhere? Even when talking with OS APIs that use the NULL define?
  • When do we make use of strongly typed enumerations? Everywhere? Or are there exceptions?
  • Rule of Zero everywhere possible and Rule of Five elsewhere? :P (I am actually a firm believer of this.)

Related topics
Summary
  • Certainly C++11
  • Some features of C++14 depending on compiler support
  • setXY({x, y})

C++14 features
  • std::make_unique - High priority
  • [[deprecated]] - Mid priority
  • constexpr - Low priority
  • generic lambdas - Low priority
Tasks
  • Requires a study of language feature support on different compilers and compiler support on different platforms.
« Last Edit: April 06, 2017, 09:08:48 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

DarkRoku12

  • Full Member
  • ***
  • Posts: 203
  • Lua coder.
    • View Profile
    • Email
Re: C++ standards
« Reply #1 on: February 22, 2017, 05:31:24 pm »
Quote
C++11, C++14, C++17?
I think C++11 would be the best option.
C++17 its too new, i think the new standard is more focused on Multithreading and Parallelization.
The most useful new library on C++17 (for SFML) would be FileSystem.

Quote
Code simplification: smart pointers, type inference, range-based for, delegating/inheriting constructors, nullptr, lambda expressions, std::function, std::tuple
All of those are good, but IMHO its better to let the user use smart pointers for its own and don't impose them.


Quote
[[deprecated]] attribute (C++14)
I think it is necessary.
« Last Edit: February 22, 2017, 06:35:37 pm by eXpl0it3r »
I would like a spanish/latin community...
Problems building for Android? Look here

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: C++ standards
« Reply #2 on: February 22, 2017, 06:16:19 pm »
Quote
C++11, C++14, C++17?
I don't think this is the right question to ask. Let's instead think about the language features that we would need in SFML 3, and then check their availability in our target compilers. Whether it belongs to C++11, 14 or 17 is less important, as some compilers may not implement all features of an old C++ version while well supporting some features of the upcoming standard.

My personal opinion: we mainly need the most important features of C++11 (brace initializers, move semantics, new standard classes) and shouldn't bother too much about newer stuff. The only exception would be C++14's [[deprecated]], so we should check whether it is well supported or not.

Then the most important point will be to have old compilers (to be defined clearly) in our CI system, and make sure that it SFML compiles on those, then we are safe for the rest of the world.

Quote
Move semantics for resource classes
Of course! Any new idiom of the language should be applied (and especially this one!), as long as it doesn't involve bleeding-edge language features.

Quote
Remove component-wise overloads in favor of initializer lists: setPosition(x,y) -> setPosition({x,y})
Keeping them wouldn't make sense.

Quote
Code simplification: smart pointers, type inference, range-based for, delegating/inheriting constructors, nullptr, lambda expressions, std::function, std::tuple
As I said, let's use everything that is available. Why would we keep old syntax when there's better one available?

Quote
[[deprecated]] attribute (C++14)
To me, this one is the only real question of this topic ;D
« Last Edit: February 22, 2017, 06:35:42 pm by eXpl0it3r »
Laurent Gomila - SFML developer

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: C++ standards
« Reply #3 on: February 22, 2017, 06:40:40 pm »
The only real reason I would be a bit annoyed at only being able to use C++11 is that the standards committee somehow managed to forget std::make_unique<T>(...) and only got around to adding it in C++14. I've written my own version of it several times, but it like I said... one of those annoying little things. ;D
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re: C++ standards
« Reply #4 on: February 23, 2017, 12:15:54 am »
Agreed, C++14 should be used: it's supported almost everywhere where C++11 is supported and fixes some problems and overlooked stuff of C++11. (make_unique is a big one!). And I also like generic lambdas a lot, they make lambda code much cleaner sometimes.

P. S. Should I start using setX({x, y}) instead of setX(x, y) if there are overloads for sf::Vector2<T> and T,T? Any noticeable differences or advantages?

P. P. S. Glad this discussion is up! I really want to see SFML moving forward and will be happy to help where I can.
« Last Edit: February 23, 2017, 12:25:03 am by eXpl0it3r »
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: C++ standards
« Reply #5 on: February 23, 2017, 01:15:23 am »
P. S. Should I start using setX({x, y}) instead of setX(x, y) if there are overloads for sf::Vector2<T> and T,T? Any noticeable differences or advantages?
If your compiler/optimizer isn't complete garbage, the 2 variants should produce the exact same code if it has access to the call site as well as the called implementation. Since sf::Vector is a template and we are making heavy use of value semantics here, the optimizer should also have an easy job of understanding what we intend to do and just "produce the right output". I stress the second part of the first sentence because it is one of the most important factors when considering what can and can't be optimized.

When producing a library, information about the source code and the original intention of the developer is lost once the intermediate form is produced. Without this information, the optimizer simply put "can't be smart about things". Both function implementations will have to be available via the external interface of a library, even if it is obvious that calling either would lead to the exact same effects. In this case temporary object construction, or whatever the technical term for it is, also can't be avoided because it would manipulate the structure of the call itself. This is why the only "magic" that happens when enabling link-time optimization (or LTCG in Visual Studio) is that a copy or some form of the original code (such as an AST) is included with the intermediate form. With it, the optimizer still has a chance to be smart even after transforming the original code into an intermediate form, treating the intermediate form a bit like a header-only library in some sense when performing the final link.

As weird as it sounds, although both setX({x, y}) and setX(x, y) do the exact same, the second has better chances of resulting in faster code when this function is at the boundary of a library.

And just food for a (thought) experiment: If we had a mechanical way to transform SFML into a header-only library, sure it will take a fair bit longer to build your application, but I can guarantee you that it will also run faster than it does "linking the traditional way". Nothing other than your usual trade-off. I've seen this many times in the past, and I myself also make use of this phenomenon when I have to write highly optimizable cross-platform code for work.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re: C++ standards
« Reply #6 on: February 23, 2017, 09:51:11 am »
binary1248, thank you for the detailed explanation! :D
The concept of being header-only is interesting... wonder what things compiler may be able to optimize with that.

Thinking about C++14 a bit more... the thing that was missing in VS for a long time is improved constexpr. I don't think that SFML needs much of it, so a lot of versions of VS will still be supported if C++14 is chosen.
Or maybe SFML can benefit from constexpr in some way?
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Jonny

  • Full Member
  • ***
  • Posts: 114
    • View Profile
    • Email
Re: C++ standards
« Reply #7 on: February 24, 2017, 01:55:56 pm »
I pretty much agree with Laurent about language features dictating which c++version to use, but in general I'd limit it to c++11 and below, as compiler support can still be a little patchy for some c++14 features (some c++14 features would even rule out all VS versions...)

  • Remove component-wise overloads in favor of initializer lists: setPosition(x,y) -> setPosition({x,y})
I'm completely in support of this.

  • [[deprecated]] attribute (C++14)
I don't beleive this is even supported in vs2015 unfortunately (yet)...

Based on this page: https://msdn.microsoft.com/en-us/library/hh567368.aspx

For me in vs2015 it also compiles but doesn't report anything, which I guess is better than failing to compile
« Last Edit: February 28, 2017, 03:06:53 pm by eXpl0it3r »

Satus

  • Guest
Re: C++ standards
« Reply #8 on: February 24, 2017, 02:22:38 pm »
Quote
I don't beleive this is even supported in vs2015 unfortunately (yet)...

It will compile, just won't report anything.

Hm, I'm not sure that the VS2015 I use at work (the one I checked this with) is updated to the latest version. Though it says Update 3.
Maybe it's something with my project setting.
« Last Edit: February 28, 2017, 03:06:25 pm by eXpl0it3r »

JayhawkZombie

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: C++ standards
« Reply #9 on: February 24, 2017, 03:20:01 pm »
It will compile, just won't report anything.

Odd.  VS 2015 reports to me when I use this tag.

eg
  [[deprecated]]
  static int TextEditCallbackStub(ImGuiTextEditCallbackData* data)...
I get the following warning:
1>sfml_project\main.cpp(121): warning C4996: 'EConsole::TextEditCallbackStub': was declared deprecated

Hmm. I'm using version 14.0.25425.01, Update 3, if that's of any importance.  I'm not sure why it'd report for some but not others.
« Last Edit: February 28, 2017, 03:07:09 pm by eXpl0it3r »

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Re: C++ standards
« Reply #10 on: February 24, 2017, 06:56:56 pm »
A few comments on the language features.

Quote
Almost always auto? Or are there cases when auto is not desired?
Do we use generic lambdas (C++14)? Or C++11 non-generic lambdas?

I think using auto almost everywhere is good. There are however places where we should refrain from using this feature, mainly for readability and sanity purposes. It's really great to replace lengthy types (e.g. iterators) or when we don't actually care about the type itself. But we should probably manually write the type we want to use if several types could be possible depending only on some subtle factors (I'm thinking about all the arithmetic types here) or if we want to avoid unintended type conversions.

C++14 generic lambda are here for a reason too: when the type of the arguments are obvious, `auto` is perfectly adapted.

In other words, I believe type inference should be used whenever possible but we should clearly tag variable with an explicit type when some confusing type deduction rules happen. I encourage people to read this SO answer: http://stackoverflow.com/a/15726504/520217


Quote
Do we rather specify the lambda return type or static_cast a return value that causes ambiguity?
Lambda should be used for simple functions, so if the return type is too complex or non-obvious in the context of the lambda, it should probably be a a function instead. With that in mind, the return type should be omitted most of the time and preferred over static_cast in my opinion.


Quote
Uniform initialization? {} everywhere or () as it was in C++03?
Using `{}` to init var is better than using `()` to trigger errors instead of weak warning when some unintended conversion occurs. However, when calling the ctor of an object with multiple arguments, we should probably use `()` when there is one overload (that we don't want to use) of the constructor taking an `std::initializer_list` to avoid potential confusion.


Quote
I assume we make use of override everywhere where it makes sense?
and `final`. :-)

Quote
When do we make use of strongly typed enumerations? Everywhere? Or are there exceptions?
I guess there could be some exceptions, but usually I'd go for strongly types enum.

Quote
Rule of Zero everywhere possible and Rule of Five elsewhere? :P (I am actually a firm believer of this.)
The rule of five has the advantage to make things clear and documented, so I'd vote for this one.

As for C++17, there are some nice features:
 - `std::optional` is a nice library addition -- not sure how we can leverage this however,
 - nested namespace declaration would be nice to have, but in itself cannot justify to use this standard,
 - attribute for enumerators would be interesting in the future to mark some as deprecated but for v3.0 this should not be required,
 - improvements on if (constexpr + if(init; cond)) could be nice to have for readability purposes,
 - structure binding would be nice for Vector2/3 (API-wise) -- considering this as a conditionally supported would be good IMO.
SFML / OS X developer

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re: C++ standards
« Reply #11 on: February 26, 2017, 09:33:36 am »
Quote
The rule of five has the advantage to make things clear and documented, so I'd vote for this one.
What do you mean by that? I think that we should use Rule of Zero as much as possible and only use Rule of Five if we really have to (e.g. if object needs a non-trivial copy-ctor => need to declare everything else). Or maybe I misunderstood you and that's what you meant?
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Re: C++ standards
« Reply #12 on: February 26, 2017, 05:59:12 pm »
What do you mean by that? I think that we should use Rule of Zero as much as possible and only use Rule of Five if we really have to (e.g. if object needs a non-trivial copy-ctor => need to declare everything else). Or maybe I misunderstood you and that's what you meant?
I guess I don't really like implicit things in my code, so that's why I'm in favour of explicitly defining (with `= default` or `= delete`) all of them. Some argue that's too verbose, but I think it's a good practice against the complexity of the rules involved for automatic special members generation (the fact that Scott Meyers dedicated an item in EMC++ is a good clue how complex this is).
SFML / OS X developer

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re: C++ standards
« Reply #13 on: February 27, 2017, 12:23:26 am »
Oh, I see. I think that it makes sense in cases where one of the following gets written: dtor, copy-ctor, copy-op=, move-ctor, move-op=. In this case some of the rules of special members generation takes place and it may be hard to remember.

But in case of simple structs and classes, which have none of these, there's no need to do this because everything gets generated always.
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: C++ standards
« Reply #14 on: February 27, 2017, 11:09:59 am »
By the way, won't we get some problems with the Android toolchain? Today I was trying to compile C++ code on Android, and the compiler threw an error at me because it didn't know std::to_string.
Laurent Gomila - SFML developer

 

anything