<brainstorm>
I've been watching through some of the videos from the
Going Native 2010 conference hosted at Microsoft this year and it's been getting me excited about some of the new features offered by C++11. In light of this, I though I'd review what C++11 features we already use and which ones we might like to use in the future. There are three reasons that we might want to use new features:
- Simpler/cleaner internal code to reduce bugs and maintenance easier
- Simpler/cleaner API to make users of the library have an easier time
- Add awesome new features to the library which wouldn't be possible otherwise -- less convincing than the other two
Current usageThe only C++11 features we use at the moment are standard library features, i.e. not language features. These are generally quite well supported in compilers and where support is lacking (i.e. VS2005 (VC++ 8.0), VS2008 (VC++ 9.0)) we currently fill in with Boost replacements. Currently we use:
- std::shared_ptr from <memory>
- std::function and std::bind from <functional>
- std::hash
- int8_t etc. <cstdint>
All these are defined in
include/PolyVoxImpl/TypeDef.h. They are maintained as #ifdefs to things like
polyvox_shared_ptr etc. We also use
<type_traits> but this has been implemented in all compilers for years now (GCC 4.3, VC++ 8.0).
Potential language features for PolyVoxThere are a few language features which it would be nice to be able to use for efficiency, error handling or syntax niceties. The following mostly excludes any features which are not going to be present in VS any time soon (even if they are already in GCC):
constexpr - GCC only but is optional improvement
There are a few places where we use semi-global constants such as the marching cubes table and randomUnitVectors for the ambient occlusion. By switching these to
constexpr we could perhaps see some speedup due to some calculations being performed at compile-time. It will require some benchmarking and investigation into where improvements can be made.
Optional interface in TypeDef.h would be like:
Code:
#if defined(CONSTEXPR_SUPPORT)
#define polyvox_constexpr_const constexpr //constexpr which falls back to const
#define polyvox_constexpr constexpr //constexpr which falls back to nothing
#else
#define polyvox_constexpr_const const
#define polyvox_constexpr
#endif
where
constexpr would be set by CMake using a
try_compile().
static_assert - GCC is fine and in VC++ since 10.0 (VS2010)
static_assert is a version of
assert() which is evaluated at compile-time. It only takes compile-time constants (e.g.
constexpr and literals) but this does include
type_traits and
sizeof(). This would allow us to implement some improved compile-time error handling for templates. Replacement functionality is included in Boost.StaticAssert but we would have to investigate how complete it is.
For example, including:
Code:
static_assert(Size == 4, "3 element vector cannot be created with 4 arguments");
into the Vector(x,y,z,w) constructor means that trying to do:
Code:
Vector<3,int> myvec{1,3,5,6};
will fail with:
Vector.inl:65:9: error: static assertion failed: "3 element vector cannot be created with 4 arguments"Maybe not the best example but is an early start. It gives no run-time overhead at all.
trailing return type - GCC is fine, VC++ since 10.0
decltype - GCC fine, VC++ since 10.0 (improved in 11.0)
Haven't had time to do a review of PolyVox for places where this would be useful but could improve the API, especially in template-heavy functions where the return-type is indirectly dependent on the argument types.
lambdas - GCC fine, VC++ since 10.0 (improved in 11.0)
There are a few places we allow the user to specify callbacks (e.g. A* pathfinder). If these callbacks could be provided using C++11 lambdas then this would improve the usability of the API. We would have to ensure that lambdas are accepted through the API even though we wouldn't necessarily be using them ourselves within PolyVox.
Code:
RaycastWithCallback<SimpleVolume, Material8> raycast(&volData,
Vector3DFloat(0,0,0),
Vector3DFloat(10,10,10),
[](const Vector3DInt32& position){return true;}
);
compiles but I haven't tested for
AStarPathfinder although it should work.
C++11/STL API consistency - No compiler dependency
This is something that Ker brought up when discussing 'range-based for loops'. It would be nice if the PolyVox API was similar to the STL where it makes sense. For example, we could support the STL iteration API on our volume sampler (and elsewhere if it makes sense).
Also, In C++11 (was also in TR1 and so is already available in many compilers) there's a new fixed-size templated array (since VC++ 2012 and GCC 4.3 but tr1::array since VC++ 2008) called std::array which you create as
Code:
std::array<int,3> myArray; //Array with 3 int elements
This clashes with, for example out PolyVox::Vector which is used like
Code:
PolyVox::Vector<3,int> myVector; //Vector with 3 int elements
It's a small inconsistency but it makes sense to align on these things. Also, PolyVox::Array is a very different beast to std::array where the former is a multi-dimensional array but the latter is more like std::vector or PolyVox::Vector.
enum classes - GCC is fine, VC++ from 11.0
They could be used for material type instead of integers to improve type-safety (discussed
here). There's likely other places we could use them too. With some macro/#IFDEF magic we might be able to only enable this usage on supporting compilers.
Language features for users of PolyVoxThere are other things we can allow the use of in user code such as initializer lists and auto (in user code):
auto - GCC is fine and in VC++ since 10.0 (v0.9 only but that should be fine)
Of course any PolyVox user can use these if they have a supported compiler without us having to change a single things. There are perhaps places where we could make use of them inside PolyVox but it would require compiler support.
initializer lists - GCC only
We should make sure that all appropriate classes (e.g.
PolyVox::Vectors) accept initializer lists as arguments. An API review will be needed to explore where they make the most sense - even if Bjarne's recommendation is to use them almost everywhere (except e.g. "int i {42}").
They can replace the need for the
ArraySizes class.
Code:
Array<3,float> array({10, 20, 30}); //3D array of 10x20x10
Vector<3,float> vec{10,4,2}; //3 element vector containing (10,4,2)
Since on the whole, they will just work, this will mostly be a documentation thing to make people aware of where they will/won't work.
Compiler supportObviously if we want to use many of these these features it would mean upgrading the minimum compiler requirement in Windows to VS2010 which as I understand is difficult for some people. It would perhaps be useful to know how many people use compilers earlier than VS2010 and whether that is due to real restrictions or just due to not upgrading so please fill out the poll attached to this post.
If we cannot increase our requirement then we will simply have to be conservative about what C++11 features we can use and fill in gaps with typedefs and conditional compilation Even if we did decide to increase the minimum requirement then it would probably not be until after our next official release (which I think Dave was planning for a few months-time).
AppendixTo the best of my knowledge, these are the currently supported compilers:
* GCC 4.4+
* VS2005 (VC++ 8.0) with Boost, VS2010 otherwise - correct me if I'm wrong
* Clang support is in progress (by me)
* Intel C++ possibly worth a look?
and finally, here are a couple of links which lay out the current state of compiler support for various C++11 language features: