Frage

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.

War es hilfreich?

Lösung

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)();
    }
  }
};

Andere Tipps

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

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().

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top