2

I am in need of mixing C code with C++ code in a computer simulation.

A C library has functions which take references to a regular array of doubles:

void position(double[3])

Another C library defines its own vector type:

void do_something(*custom_vector)

And my front-end (in C++) uses boost::numeric::ublas::vector.

In the first case, I have a lot of places with this kind of code:

double tmp[3];
position(tmp)
boostvec r(3);
r(0) = tmp[0]; r(1) = tmp[1]; r(2) = tmp[2];
// continue working with r

also

custom_vector *v;
do_something(v);
boostvec r(3);
r(0) = v[0]; r(1) = v[1]; r(2) = v[2];

Internally, all the types are ultimately vector containers, but their slight implementation differences are causing a lot of boilerplate explosion. I am also dealing with a lot different versions of double (some define realtype (which is a double), others define number (which is a double), etc).

How do you deal with this situation?

Thank you.

Escualo
  • 40,844
  • 23
  • 87
  • 135
  • 1
    Supply standalone conversion functions? – Thomas Matthews Oct 07 '11 at 19:13
  • @ThomasMatthews: I thought of this, but I still would like to explore the possibility of passing the underlying boost array to the C functions (maybe it is a terrible idea, but I thought I should ask;) – Escualo Oct 07 '11 at 19:27

2 Answers2

2

As long as both source and destination types support the standard iterator interface (which is true for std::vector, arrays, and every Boost sequence type I can think of; so you just need to fix your custom_vector), and as long as there are implicit conversions possible between the numeric types, you should be able to just use std::copy.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • I tested this and it works. Now, is there a way of avoiding the temporary storage? In other words, could I pass the underlying boost array to the C functions? – Escualo Oct 07 '11 at 19:26
  • 1
    @Arrieta: If the underlying representation is like an array (and it almost always is), `&a[0]` should work. – David Thornley Oct 07 '11 at 19:38
2

If you are translating between two data types like that, you probably should be writing a lot of boiler plate. It's always going to be the same operation, no matter how much lipstick you put on it.

When you see typedefs for things like realtype, that is a code smell for me that someone is abstracting data too soon. Writing abstractions around data at lower levels tends to make interfaces "blow up" like this. If you use data containers in the dumbest way, you are generally better off. Don't protect invariants with them, just store data. Make abstractions at algorithm level and leave the data in its simplest form.

It might make sense to refactor the other code to all use something consistent, but usually its old or external code. In your new development, be sane and use vectors. Write adapters to translate between them and just let the old code continue to suck behind your veneer.

The happiest I've been with keeping these sorts of problems from getting horribly kludgy is to use pointers and a length. This goes against most advice, admittedly.

void foo(double *data, size_t len);

It makes for ugly (and error prone) code, but it's the lowest common denominator. If you can hide it in private implementation that is way better obviously.

I just ended up writing a lot of helpers that weren't able to be reused. As a result, the code had terrible locality and my intentions were not obvious.

Tom Kerr
  • 10,444
  • 2
  • 30
  • 46
  • great post. I specially like the "let the old code continue to suck behind your veneer" - I will be aiming for that. – Escualo Oct 07 '11 at 23:10