【问题标题】:How to create new typename from the typename pass in a template class如何从模板类中的类型名传递创建新的类型名
【发布时间】:2014-02-13 09:36:57
【问题描述】:

假设我有一个模板类

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

在这个堆栈类中,我调用了一个工具类,它也是模板。但其处理的数据类型是 UltityDATA 类型。也就是说,如果我们使用以下代码创建类堆栈的对象

 stack<MyData> s

在内部它应该调用 UltityMyData。我不想将 UltityMyData 结构暴露给客户。我已经编写了将 MyData 转换为 UltityMyData 的实现。只有我的要求是当我调用我的库类时如何将 DATA 类型名转换为 UtilityDATA 类型名。


根据您的建议,我已经编写了以下代码

#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;
      }
}; 

但我收到错误,因为 错误:'DDST' 未在此范围内声明
基本上预处理器只附加两个值并创建一个新类型。根据我的理解,模板将在编译时进行转换。 DDS#T 将其作为一种新的数据类型而不是模板类型。

【问题讨论】:

  • UtilityMyData 是否也设计为模板类?如果您出示声明会很有帮助。
  • 不,这是不可能的,模板类(在您的情况下为 Stack)不知道用于实例化的实际类型,因此 C++ 语言内部没有办法允许这样做。跨度>

标签: c++ templates


【解决方案1】:

您可以根据需要拥有一个专门用于类型定义的结构

// 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;
};

然后你就可以使用这个辅助类了

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

【讨论】:

    【解决方案2】:

    您可以使用traits 模式:

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

    并像这样实例化:

    stack<MyData, UtilityMyData> s;
    

    但是,这将要求您的用户明确命名实用程序类。如果您不介意使用预处理器,您可以使用宏:

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

    然后你会写:

      STACK(MyData) s;
    

    它并不漂亮,但它可能会为您的用户所接受

    【讨论】:

    • 为什么是宏!那太糟了。只需使用默认模板参数,就像所有标准库容器一样
    • @Manu343726 - 是的,宏很可怕,但如果你阅读了这个问题,你会发现你不能使用默认模板参数
    • 不,只是说 UtilityMyData 不得公开。创建像default_data这样的标签类型,将其用作默认参数,并在内部使用它来选择UtilityMyData(例如std::conditional)
    • 另外参数默认为MyUtility的一点是用户不必写MyUtility。所以这个解决方案是完全合理的
    • @Manu343726 - 或许可以发布您的建议作为答案
    【解决方案3】:

    也许您可以将其移至某个内部模板结构?

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

    更新:对不起,我误解了你的问题。对于一些具体类型 MyData 和 UtilMyData 你可以使用 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      • 2015-10-06
      • 1970-01-01
      • 1970-01-01
      • 2013-01-23
      相关资源
      最近更新 更多