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

Determining a template type at later point in time C++

我想尝试编写一些可以处理不同数据类型的通用代码。一旦设置了这些数据类型,它就会在整个实例期间保持不变。

我认为展示我正在尝试做的事情比描述它更容易。

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

现在,这不会编译,因为 helper 没有模板参数,但是有没有办法让我可以在稍后的时间点设置参数(比如在有用户输入之后,如例子)? 一旦设置了参数,就不会改变它的用例。我知道这是一个简单的例子,我可以只是做一个cout中的switch-case,但这是我要完成的概念。

不幸的是我坚持使用 C++11 并且没有增强库,否则我想我可以使用 std::any,我想我可以使用 void 指针,但是我会指定调用 reinterpret_cast.

时的数据类型

如果有任何我可以提供的额外信息或任何我可以解决的问题,请告诉我!

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

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

但是我认为没有办法在 base 中声明 virtual T getData()

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

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

template <typename T>
class helper : public AbstractHelper

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

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

和select所需的处理程序:

 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;

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