views:

137

answers:

4

I have two c++ programs that need to have a map type -> int that is known at compile time and equal between the two programs. Furthermore, I'd like to automatically make sure at compile time that the map is one-to-one. How would you solve that? (c++0x-extensions are allowed). The first part is easy: Share a

template < typename T > struct map;
template <> struct map <...> { enum { val = ...; }; };

between the programs. (The second part means that I don't want to accidently define the same val for two different types somewhere in my programs.)

+1  A: 

How about using boost::mpl::map? Share something like:

// Include your headers

using namespace boost::mpl;
typedef map<
      pair<1,MyFirstClass>
    , pair<2,MySecondClass>
    , pair<3,MyThirdClass>
    > m;
mlimber
+6  A: 

One way to ensure uniqe ids is to abuse friend function definitions

template<int N>
struct marker_id {
  static int const value = N;
};

template<typename T>
struct marker_type { typedef T type; };

template<typename T, int N>
struct register_id : marker_id<N>, marker_type<T> {
private:
  friend marker_type<T> marked_id(marker_id<N>) {
    return marker_type<T>();
  }
};

template<typename T>
struct map;

template<>
struct map<int> : register_id<int, 0> { };

// The following results in the following GCC error
// x.cpp: In instantiation of 'register_id<float, 0>':
// x.cpp:26:43:   instantiated from here
// x.cpp:14:29: error: new declaration 'marker_type<float> marked_id(marker_id<0>)'
// x.cpp:14:29: error: ambiguates old declaration 'marker_type<int> marked_id(marker_id<0>)'
//
//// template<>
//// struct map<float> : register_id<float, 0> { };
Johannes Schaub - litb
Cool! This looks like the perfect solution, as it frees me from having to specify all types in a list.
Thomas
@Thomas now it also shows the conflicting types in the error message.
Johannes Schaub - litb
A: 

They don't do it strictly at compile time, but this pair of functions will automatically generate a unique ID for each type passed to them:

template<class T>
int generate_type_id() {

    static int value = 0;
    return value++;

}

template<class T>
int type_id() {

    static int value = generate_type_id<T>();
    return value;

}

And you should be able to ensure that the two applications share the same identifiers for a given type by explicitly invoking the functions in order in both projects:

type_id<int>();
type_id<Foo>();
type_id< map<string, pair<int, Bar> >();

Yes, this forces you to write a list of all involved types, but you can toss it in a header, #include it between them, and at least avoid code duplication. This also absolves you of having to come up with unique IDs for each type on your own, as Johannes Schaub's answer does, though his has the advantage of being done completely at compile-time and thus statically checked by the compiler. I'm only offering an alternative.

Jon Purdy
A: 

An easy approach might be to just share the same class in both programs.

Re-use is one of the objectives to OOP.

A class that encapsulates the map and its initialization can be created and then used in both C++ programs.

skimobear