1

I'm trying to figure out a way to use Boost::MPL to generate a typename which is the concatenation of a template parameter and a string.

I have pairs of classes which are named: X and XProvider. The latter is a factory class which instantiates objects inherited from the former type.

The template class is intended to manage the instantiation of types at runtime: it contains, among other things, an unordered_map and some other misc. members.

What I am ultimately trying to achieve is a metafunction that looks something like this:

Given the class

template <typename T>
class Plugin_Manager{

    using Base_Type = T;

    std::vector<Get_Provider_Type<Base_Type>::type *> m_provider_collection;

      */ ... /*

};

Where Get_Provider_Type<T> is a metafunction which returns a typename TProvider.

Based on this answer, I think that the metafunction should look something along the lines of this:

    template < typename Str1, typename Str2 >
    struct concat : boost::mpl::insert_range < Str1, typename boost::mpl::end<Str1>::type, Str2 > {};


    template <class T> struct Get_Provider_Type{
        typedef typename boost::mpl::string<boost::mpl::c_str<T>::value>::type Base_Name;
        typedef boost::mpl::string<'Prov', 'ider'> Suffix;

        typedef typename concat<Base_Name, Suffix>::type type;
    };

However, I am really not understanding mpl::c_str or mpl::string or their correct usage, and I cannot follow the error messages that I am receiving. The code as written above gives me the error message:

    error C2039: 'value_type' : is not a member of 'foo'

(foo here being the template argument -- Plugin_Manager<foo>)

I realize that I can likely make this work if I use a large macro rather than c++ template, but I would really like to avoid that if at all possible.

I'd really appreciate any suggestions.

Thanks- Shmuel

Community
  • 1
  • 1
Shmuel Levine
  • 550
  • 5
  • 18
  • 1
    Macros are the only way to create new identifiers by combining existing ones, sorry. Templates can't do it. – Mark Ransom Dec 04 '14 at 21:34
  • What you are saying does not make much sense to me. If you intend to use the expression `Get_provider_Type::type` to specify the template argument of a vector all you need is to provide a type. You don't need to generate a name for it at all. – pmr Dec 04 '14 at 21:35
  • Perhaps _generate_ is the wrong term. `Plugin_Manager` needs to contain a `std::vector` -- I'd like to have a metafunction `Get_Provider_Type::type` which will return for me the type `fooProvider`, but I do not know how to write this metafunction (or even if it's possible -- per @MarkRansom's comment above). – Shmuel Levine Dec 04 '14 at 21:58
  • @ShmuelLevine It's not possible. It might be better to simply provide a `public: typedef fooProvider provider;` inside of `foo`. This way each class can define their own provider type and don't have to follow any particular naming convention. Then you just have `typename T::provider` as the provider type. – cdhowie Dec 04 '14 at 22:04
  • @cdhowie, all-in-all, that is a sensible approach, and since it only needs to be in the base class, it has a minimal impact. I don't know why I didn't think of this beforehand... I guess I've had TMP on my mind lately and looking to learn a little more than I did yesterday... – Shmuel Levine Dec 04 '14 at 22:19
  • @ShmuelLevine *"it only needs to be in the base class"* -- I'm not quite sure I understand what you mean here, but if I do then this may not be true. If you have `class bar : public foo` and `boo` needs its own `barProvider` then you need to shadow the `provider` typedef in `bar` to get the right behavior. – cdhowie Dec 04 '14 at 22:23
  • @cdhowie, `barProvider` itself is derived from `fooProvider`. The notation xxxProvider is consistent throughout, but in all cases, wherever I have `bar : public foo`, I will also have `barProvider : public fooProvider`. That is the convention that is used in [this framework](http://pluma-framework.sourceforge.net/) which I have been tryign to use to deal with the boilerplate code. – Shmuel Levine Dec 04 '14 at 22:28
  • @ShmuelLevine Right but if you only put `typedef fooProvider provider;` in `foo`, then `bar::provider` is `fooProvider`. You need the typedef at each level to point to the right provider type. `bar::provider` won't magically become `barProvider` just because `barProvider` derives `fooProvider`. – cdhowie Dec 04 '14 at 22:34
  • @cdhowie Right. Of course it will not magically become barProvider; however, in this context, it is accessed polymorphically through fooProvider*. I intended my comment -- that adding the `typedef fooProvider provider;` will suffice -- to be specific to my own application, not in the general sense. – Shmuel Levine Dec 05 '14 at 04:24
  • @ShmuelLevine Right, okay -- as long as you aren't using `T::provider` to actually *construct* the provider object. (I can't see your code so I assume based on what you've said that this isn't the case.) Cheers! – cdhowie Dec 05 '14 at 04:28

1 Answers1

2

Well, you can't get a typename from concatenating strings with template parameters, but if your intention is...

I'd like to have a metafunction Get_Provider_Type::type which will return for me the type fooProvider

You can simply define the type in foo:

struct foo {
    using provider = fooProvider;
};

If you need it, you can implement your "metafunction" that will work with all types that define T::provider

template<class T>
struct Get_Provider_Type {
    using type = typename T::provider;
};

Which can be useful if you can't modify foo to define the type. Then you can specialize Get_Provider_Type instead:

template<>
struct Get_Provider_Type<foo> {
    using type = fooProvider;
};
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Thanks. I don't know why I didn't think of this approach before. It is elegant and will work surprisingly well for my specific application (as mentioned in the comments above on my original post). I guess I had my mind set on finding a solution with mpl and concatenation so this didn't even occur to me. Thanks! – Shmuel Levine Dec 05 '14 at 04:26
  • I thought C++'s template system was Turing-complete? Doesn't that imply that there is some way to do it? – Cognitive Hazard Sep 22 '17 at 04:33