在以后的时间点确定模板类型C ++

时间:2018-12-14 18:22:13

标签: c++ c++11 generic-programming

我正在尝试编写一些可以处理不同数据类型的通用代码。一旦设置了这些数据类型,则在实例运行期间它将保持不变。

我认为,比起描述,更容易展示我的意图。

helper.h

#include <iostream>
#include <type_traits>
#include <utility>
#include <string>
#include <sstream>
#include <stdexcept>
using namespace std;
template <typename T>
class helper
{
public:
    helper()
    {
      stringstream temp;
      if(is_same<T, short>::value)
      {
        temp << 1;
      }
      else if(is_same<T,long>::value)
      {
        temp << 1024;
      }
      else if(is_same<T, char*>::value)
      {
        temp << "Hello";
      }
      else if(is_same<T, string>::value)
      {
        temp << "Hello World";
      }
      else
      {
        throw invalid_argument("Error in helper: Unknown data type" + to_string(__LINE__) +  string(__FILE__));
      }

      temp >> data;
    }


    T getData()
    {
      return data;
    }

  protected:
    T data;
};

call.cpp

#include <iostream>
#include "helper.h"
using namespace std;

int main()
{
  helper<> my_helper;

  int data;
  cin >> data;
  switch(data)
  {
    case 1:
      my_helper = helper<short>;
      break;
    case 2:
      my_helper = helper<long>;
      break;
    case 3:
      my_helper = helper<char *>;
      break;
    default:
      my_helper = helper<string>;
      break;
  }
  cout << my_helper.getData() << endl;
  return 0;
}

现在,由于助手没有模板参数,因此无法编译,但是有一种方法可以在以后的时间点设置参数(例如,在示例中显示用户输入之后) ? 设置了参数后,就不会再有使用情况了。我知道这是一个简单的示例,我可以在其中执行cout switch-case,但这是我要完成的概念。

不幸的是,我坚持使用C ++ 11并且没有boost库,否则我认为我可以使用std::any,我认为可以使用void指针,但是随后我必须指定调用reinterpret_cast时数据类型是什么。

如果我可以提供其他信息或可以清除的任何信息,请告诉我!

2 个答案:

答案 0 :(得分:2)

helper<short>是一种类型,而helper<char *>是另一种完全不兼容的类型。两者均不能分配类型helper<>。为此,您可以使用基类:

class base {
   virtual ~base() = default;
};

template <typename T>
class helper: public base
{
    // your code
};


int main()
{
  std::unique_ptr<base> my_helper;

  int data;
  cin >> data;
  switch(data)
  {
    case 1:
      my_helper.reset(new helper<short>);
      break;
    case 2:
      my_helper.reset(new helper<long>);
      break;
    case 3:
      my_helper.reset(new helper<char *>);
      break;
    default:
      my_helper.reset(new helper<string>);
      break;
  }
  //cout << my_helper->getData() << endl;
  return 0;
}

但是我不认为有一种方法可以在virtual T getData()中声明base

答案 1 :(得分:1)

问题的答案取决于您要实现的目标。 所以第一。不要忘记,模板和OOP通常是正交的。每个模板专长都是与他人无关的新类型。因此,将所有专业转换为相同类型的唯一方法是从一个基类继承。所以

class AbstractHelper
{
public:
   virtual ~AbstractHelper() {}
};

template <typename T>
class helper : public AbstractHelper

第二。您需要回答这个问题-模板类的数据可以由单个处理程序处理还是不切实际(基于性能考虑,实现复杂性等),假设它可以(例如,作为字符串)。在这种情况下,您需要:

class AbstractHelper
{
public:
   virtual string getDataString() { return ""; }
   ...

template <typename T>
class helper : public AbstractHelper
{
public:
string getDataString()
   {
      return to_string(data);
   }

如果这不可接受,则需要回答这个问题,是否可以完全封装数据处理?假设可以。然后

class AbstractHelper
{
public:
   virtual void printData() {  }
   ...

template <typename T>
class helper : public AbstractHelper
{
public:
void printData()
   {
      cout << data << endl;;
   }

最后,最困难的选择是您需要对所有类型进行不同的处理,并且无法对其进行封装。然后,您需要确定源类型并使用动态类型转换:

enum Type
{
   TYPE_SHORT,
   TYPE_LONG,
   TYPE_STRING
...

class AbstractHelper
{
protected:
   Type type_;
public:
   Type getType() { return type_; }
......

template <typename T>
class helper : public AbstractHelper
{
public:
   helper()
   {
      stringstream temp;
      if (is_same<T, short>::value)
      {
         temp << 1;
         type_ = TYPE_SHORT;
      }
      else if (is_same<T, long>::value)
      {
         temp << 1024;
         type_ = TYPE_LONG;
      }
      ...

并选择所需的处理程序:

 switch (my_helper.getType())
   {
   case TYPE_SHORT:
      cout << dynamic_cast<helper<short>&>(my_helper).getData() << endl;
      break;
   case TYPE_LONG:
      cout << dynamic_cast<helper<long>&>(my_helper).getData() << endl;

请不要对手动代码的数量感到困惑-宏和模板可以大大减少它。