Topic: constexpr, templates, and concepts


Author: Ken Camann <kjcamann@gmail.com>
Date: Fri, 16 Jan 2009 15:44:35 CST
Raw View
Lately I've been reading through a lot of the standards documents and
playing with ConceptGCC to figure out how to work with concepts in
their current form.  I figure that as I write code today, I can ease
retrofitting concepts onto it later if I understand the direction that
the concepts feature is heading in.

One of the problems I've been having is that the library I am
designing should probably make heavy use of non-type template
parameters.  I want to do high performance scientific computing and
most of the time I want to ensure that certain geometric objects (like
vectors, polygons) have a compile-time determined size.  Sometimes
certain operations only make sense for certain size (cross product for
3 dimensional vectors, for example) or finding the inverse of a matrix
known at compile time to be of a certain form (e.g., always
orthogonal) can be done much faster than in the general case.

If a compiler were constructed from the standard as it is today, would
the code following work?

concept Vector <typename T>
{
   typename SizeType;
   constexpr static SizeType T::size (void);  // requires<T> means
T::size() is ok to call
};

template <typename T>
requires Vector<T> && True<T::size() == 3> // legal (future) C++?
void crossProduct (const T& t)
{
}

or

template <Vector V>
requires True<V::size() == 3> // legal (future) C++?
void crossProduct (const V& v)
{
}

Things get a little bit trickier if you have the fixed size built into
the concept itself, e.g., the concept of a 3 dimensional vector.  I'm
not sure if any of this is even supposed to work, given the current
standard, because no one really shows examples like this.  ConceptGCC
doesn't have constexpr, so I tried to do this which crashed the
program:

concept Vector <typename T, std::size_t N>
{
   ...
};

// A 3 dimensional vector implementation
template <typename T>
class CartesianVector3
{
   typedef T NumericType;
   typedef std::size_t SizeType;
   static const SizeType size = 3;

   // T should be std::FloatingPointLike and not typename but
   // then it would be an incomplete type and I couldn't do this:

   T mData[3];

   // Should "late_check T mData[3]" have worked (it didn't)?
   // Do I need to late_check the whole parameter?
};

template <FloatingPointLike F>
concept_map Vector<CartesianVector3, 3>
{
  //...
};

template <typename T>
requires Vector<T, T::size> // ConceptGCC crashes parsing this
line...illegal?
void crossProduct (const T& t)
{
}

Things get even more unusual if CartesianVector3 is instead itself a
template with non-type parameters.  In that case I'm not even sure how
the function would have to be written.

template <typename T, std::size_t N>
class CartesianVector;

I'm not even sure how to write the concepts/concept_maps/functions in
this case.  I've tried a lot of different things, they're all wrong or
crash GCC and in general make me feel like I really don't understand
whats going on at all.  Is there a way things like this can/should be
done, if indeed they should be done at all?

-Ken

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]