> and then do the memory management by hand and use dynamic casts

Requiring users to do dynamic casts is probably the wrong thing to do.  

> std::map<std::pair<mat, std::pair<mf, mt> >, mt_xxx_struct >

Aren't mat, mf, & mt all ints?  Couldn't you get away with a ``std::vector<int>``?  Or better yet, we could have a struct that has `operator<()` defined that specifies the mat, mt, mf nums a la

```c++
struct endfid {
  int mat;
  int mt;
  int mf;
}
```

It seems like the right thing to do would be some combination of these two.  Have the struct-specific maps that are maps to pointers.  Then have a top-level lookup function that is templated on the mt struct type and takes the mat and mf as args and returns the appropriate struct type.  This has to be template rather than overloaded because the differences are on the return type not on the args.