In order to familiarize myself with Boost.Proto I am trying to build yet another expression template library for floating-point vectors of fixed but arbitrary size by adapting the TArray example from the user's guide. The first thing I do is to define my vector class:
typedef double real;
// Forward-declare an expression wrapper
template<typename Expr>
struct vector_expr_wrapper; // line 13
class FPVector : vector_expr_wrapper< proto::terminal< FPVector >::type > { // line 16
public:
FPVector() : numElements(0), elements(0) {}
FPVector(size_t n) : numElements(n), elements(new real[n]) {}
~FPVector() { delete[] elements; }
real& operator[](size_t i) { return elements[i]; }
template<typename Expr>
FPVector const& operator=(vector_expr_wrapper<Expr> vec_expr) {
for(size_t i=0; i<numElements; i++) {
elements[i] = vec_expr[i];
}
return *this;
}
private:
size_t numElements;
real * elements;
};
vector_expr_wrapper
also overloads its operator[]
to evaluate itself with a vector_context
derived from proto::callable_context
that returns vector[index]
for FPVector
terminals.
When I compile my code and call it with a very simple statement (a = b + c;
) I get the error message:
../main.cpp:16:18: error: invalid use of incomplete type ‘struct vector_expr_wrapper<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<FPVector>, 0l> >’
../main.cpp:13:8: error: declaration of ‘struct vector_expr_wrapper<boost::proto::exprns_::expr<boost::proto::tagns_::tag::terminal, boost::proto::argsns_::term<FPVector>, 0l> >’
../main.cpp: In function ‘int main()’:
../main.cpp:121:8: error: no match for ‘operator+’ in ‘b + c’
and then g++ lists the possible candidates stuff...
What I understand from that is that I have to give the whole definition of vector_expr_wrapper
before definig FPVector
but I cannot do so because everything else in vector_expr_wrapper
depends on FPVector
(the grammar, the evaluation context...)
How can I solve this (i.e. how should I layout my classes)?
The TArray example circuments this problem -- I guess -- by defining their array class very late and by specifying its type with int[3]
before, which I think I cannot reproduce in my context.
Thank you very much for your help!
Here is my solution:
The code you show has a number of problems:
You can't inherit from an incomplete class template (
vector_expr_wrapper
) from a (concrete) class (FPVector
). Also, yourFPVector
type is trying to contain a copy of itself.proto::terminal
is a wrapper around an object type. Think of it as a stand-in for the thing itself, but with some extra Proto spice. Then inheriting from it or from something that inherits from it is not going to fly.The only real trick in the code I posted is the use of
proto::is_proto_expr
. This is a nasty hack to get ADL to kick in an find the operator overloads defined in theboost::proto
namespace. The thing is described in detail in the warning at the bottom of "The extends<> Expression Wrapper" section of proto's docs.