0

I have a C++ problem. I want to generate a type based on the type arguments passed to a templated function of it.

Let me illustrate it.

class A  {

   template<class B> M() { }

   void Z() {

   // NOTE: Here I want to call to X on each type that was feed it to M.
   X<N1>();   
   X<N1>();
   ...
   X<NN>();

   }

   template<class B> X() { }
   };

For example

   A a;

   a.M<int>();
   a.M<double>();

then a.Z() executes ...

   X<int>();
   X<double>();

Another example to take into account unique types

   A a;

   a.M<int>();
   a.M<int>();
   a.M<double>();
   a.M<double>();

then a.Z() will still executes ...

   X<int>();
   X<double>();

Note that I am generating the type A based on the calls to M. OK! I think that for that class A that's conceptually impossible because A is not templated type and then it can not vary in that way, In fact that's not possible for any type in C++ (I think). But I want you to get the idea.

I am looking forward for a way to confront this problem using meta-programming, but any advice or solution or reference is welcome.

  • Why do you want to do this? – ecatmur Feb 07 '14 at 16:58
  • @ecatmur we are using generic programming and some kind of optimization when creating some kinds of objects and we need to clean resources in a very clean way – Eric Javier Hernandez Saura Feb 07 '14 at 17:00
  • 1
    If you want `a.Z()` to expand at compile-time, the trouble is that statements `a.M();` and `a.M();` are consecutive at run-time but entirely unrelated at compile-time. How about `A a; a.Z();` or `A a; a.M().Z();`? – aschepler Feb 07 '14 at 17:18
  • 1
    This cannot work at compile-time, as there can be different instantiations in different Translation Units. If you restrict this to a single TU, you could use [something like this](http://stackoverflow.com/questions/4790721/c-type-registration-at-compile-time-trick). – dyp Feb 07 '14 at 17:18
  • Why do you think the above is a good solution to your problem? The clean way to clean resources in C++11 is to use RAII types that do the cleaning for you. Which looks very little like the above. – Yakk - Adam Nevraumont Feb 07 '14 at 18:45
  • @Yakk In fact, we are using RAII, but trust me I can't give you all the details. My answer above it is not self explaining ... – Eric Javier Hernandez Saura Feb 07 '14 at 19:18
  • "My answer above it is not self explaining ..." -- that sentence makes no sense. The above question looks like a classic X/Y problem, where you have thought "I have a problem Y, and if I can do X it will be solved, so I will ask about X". But X as formulated cannot be done (at least not elegantly) -- maybe there are easy and useful solutions to Y, but because you aren't telling people what Y entails (at most vaguely mentioning it), nobody can help you with those neat solutions. – Yakk - Adam Nevraumont Feb 07 '14 at 19:23

3 Answers3

4

No metaprogramming needed.

class A {
  using XPtr = void (A::*)();
  std::vector<XPtr> x_calls;
  std::set<std::type_index> x_types;

  template <typename B> void X() { ... }

public:
  template <typename B> void M() {
    bool is_new = x_types.insert(std::type_index(typeid(B))).second;
    if (is_new)
      x_calls.push_back(&A::X<B>);
    ...
  }

  void Z() {
    for (auto&& ptr : x_calls) {
      (this->*ptr)();
    }
  }
};
Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
2

First off, I think you're interface isn't really MPL. To be MPL you'd call it more like typedef MyType mpl::vector<int, double> and then find a way to build a type that called X<...> for each type. However...

#include <iostream>
#include <typeinfo>
#include <vector>
#include <functional>
#include <algorithm>

using namespace std;

template< typename T>
void X() {
    cout<<typeid(T).name()<<endl;
}

struct A {
  vector< function<void(void)> > callbacks;
  void z() { 
    for( auto a : callbacks ) a();
  }

  template<typename T>
  void M() {
    callbacks.push_back( [](){ X<T>();} );
  }
};

int main() {
    A a;
    a.M<int>();
    a.M<double>();
    a.z();
    return 0;
}

does what you want.

$ g++ --std=c++11 && ./a.out
i
d
Ss

See it live

KitsuneYMG
  • 12,753
  • 4
  • 37
  • 58
1

You can achieve similar functionality using boost::fusion::set and boost::mpl.

class A {
    struct functoid {
        template<typename T>
        void operator(T t)
        {
             /* do something */
        }
    }
    template<class B> M() {

        boost::mpl::for_each<B>(functoid());
    }
}

A a;
a.template M<boost::fusion::set<int, double, ...>>();

But, in this case, you need to know the actual types, or, register some callback in operator().

nothrow
  • 15,882
  • 9
  • 57
  • 104