简体   繁体   中英

How to create new typename from the typename pass in a template class

Suppose I am having a template class

template <class DATA>
class Stack { 
  //Some implementation
}

Inside this stack class I am calling a utility class which is also template. But datatype its handling is of type UltityDATA. That is if we create the object of class stack using following code

 stack<MyData> s

Internally it should call UltityMyData . I dont want to expose UltityMyData stucture to the clients. I have already written implementation for coverting MyData to UltityMyData . Only My requirement is how to convert DATA typename to UtilityDATA typename when I am calling my library class.


I have wrritten following code as per your suggestion

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>

using namespace std;
struct RTI 
{
    int a;
};

struct DDSRTI 
{
    int b;
};

// other specialization you might need in the future
 template<class Data>
 struct DDS
{
    typedef DDSData type;
};
template <class T>
class MyStack { 
  private: 
   T a;
  public: 
      MyStack()
      {
       //  cout<< a;
      }
}; 
#define STACK(T) Stack<DDS##T>
template <class T>
class Stack { 
  private: 
  Stack<T> a;
  STACK(T) b;
  public: 
      Stack()
      {
         ///cout<< a;
      }
}; 

But I am getting error as error: 'DDST' was not declared in this scope
Basically preprocessor only appending two values and creating a new type. As per my understanding template will be convert at the time of compilation. DDS#T its taking as a new data type not as template type.

You could use a traits pattern:

template <class DATA, class TRAITS>
class Stack 
{ 
  //Some implementation
}

and instanciate like this:

stack<MyData, UtilityMyData> s;

However, this will require your users to explicitly name the utility class. If you don't mind using the pre-processor you could use a macro:

#define STACK(T) Stack<T, Utility##T>

And then you'd write:

  STACK(MyData) s;

It's not pretty, but it might be acceptable to your users

Maybe you can just move it to some internal template structure?

template <class DATA>
class Stack {
  public:   
    template <class Data>
      struct UtilData {
        template <class... Args>
          UtilData(Args&&... args) : d{std::forward<From>(args)...} {}
            // other operators
          Data d;
        };

    void push(DATA&& d) {
      s.push(UtilData<DATA>{d});
    }
  std::stack<UtilData<DATA>> s;
};

Update: Sorry, I misunderstood your question. For some concrete types MyData and UtilMyData you can use boost::mpl::map:

using boost::mpl::pair;
using boost::mpl::map;
using boost::mpl::at;

typedef map<pair<SomeOther, Some>/*, other pairs of types here*/> TypeMap;

at<TypeMap, SomeOther>::type s; // s has type Some

You can have a struct specializing a type definition according to your needs

// non specialized type
template<typename T>
struct UtilType {};

// specialization for DATA
template<>
struct UtilType<DATA>
{
    typedef UtilityDATA type;
};

// other specialization you might need in the future
template<>
struct UtilType<NewType>
{
    typedef UtilityNewType type;
};

You would then use this helper class as so

template<typename T>
class Stack
{
    // .....
    typedef typename UtilType<T>::type dataType; //converts DATA typename to UtilityDATA
    // .....
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM