【问题标题】:how to do an if else depending type of type in c++ template? [duplicate]如何根据 c++ 模板中的类型类型执行 if else ? [复制]
【发布时间】:2013-03-04 10:51:52
【问题描述】:
// template specialization
#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
    T element;
  public:
    mycontainer (T arg) {element=arg;}
    T increase () {

    //if(T.type==int)//how to do this or something similar?
    //do this if an int
    return ++element;

    //if(T.type==char)
     //if ((element>='a')&&(element<='z'))
      //element+='A'-'a';
      //return element;

    }
};

我知道如何编写模板特化并为 char 类型做一个单独的整个类定义。

但是,如果我想在一个代码块中处理所有事情呢?

如何检查 T 是 int 还是 char?

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    你可以使用typeid:

    if (typeid(T) == typeid(int))
    

    或者你可以使用std::is_same 类型特征:

    if (std::is_same<T, int>::value)
    

    【讨论】:

    • 如果只有static_if...也许这会解决同样的问题
    • 有很多关于static_if 的提议,但都遇到了问题。 SG8 最近写了an analysis of the proposals
    • @JosephMansfield 您提供的链接没有预览。
    • C++17 引入了 constexpr if,这可能就是你想要的。
    【解决方案2】:

    您想要的可能类似于compile-time if。 不幸的是,C++11 没有对这种语言结构的原生支持。

    但是,如果您只想检查两个类型是否相同,std::is_same&lt;&gt; 类型特征应该可以帮助您:

    #include <type_traits> // <== INCLUDE THIS STANDARD HEADER
    
    // class template:
    template <class T>
    class mycontainer 
    {
        T element;
    public:
        mycontainer (T arg) {element=arg;}
        T increase () 
        {
            if (std::is_same<T, int>::value)   // <== THIS IS HOW YOU WOULD USE IT
                return ++element;
    
            if (std::is_same<T, char>::value)  // <== THIS IS HOW YOU WOULD USE IT
            {
                if ((element>='a') && (element<='z'))
                    element+='A'-'a';
            }
    
            return element;
        }
    };
    

    但是,请记住条件是在运行时评估的,即使is_same&lt;T, int&gt;::value 的值在编译时是已知的。这意味着bothtrueif 语句的false 分支必须编译

    例如,以下内容是不合法的:

    if (std::is_same<T, int>::value)
    {
        cout << element;
    }
    else if (std::is_same<T, my_class>::value)
    {
        element->print();  // Would not compile when T is int!
    }
    

    此外,正如 Xeo 在 cmets 中正确指出的那样,编译器可能会发出警告,因为您的条件将始终评估为 truefalse,因此两个分支之一将包含无法访问的代码。

    【讨论】:

    • C++ 确实有编译时if:它被称为函数重载解析。
    • 这也意味着您会收到未使用分支的警告。更好的形式是标签调度,我认为这是我的答案,但简单的重载也可以完成这项工作。
    • @JamesKanze:这与真正的 static if 构造完全不同。
    • 你可以通过简单的重载决议来做到这一点,但它不容易扩展(例如,如果他想为整数类型做一件事,为所有其他类型做另一件事)。跨度>
    • @AndyProwl 达到了同样的目的。
    【解决方案3】:

    您可以使用显式模板特化

    #include <iostream>
    using namespace std;
    
    // class template:
    template <class T>
    class mycontainer {
        T element;
      public:
        mycontainer (T arg) {element=arg;}
        T increase();
    };
    
    
    template<>
    int mycontainer<int>::increase(){
        return ++element;
    }
    
    template<>
    char mycontainer<char>::increase(){
        if ((element>='a')&&(element<='z'))
           element+='A'-'a';
        return element;
    }
    
    int main(){
            mycontainer<int> A(10);
            mycontainer<char> B('x');
    
            cout << A.increase() <<endl;
            cout << B.increase() <<endl;
            return 0;
    }
    

    【讨论】:

    • 我喜欢这个解决方案
    • 不依赖任何成员函数参数的优雅解决方案。我需要在成员函数中将*userp 转换为T 模板类型,例如static size_t WriteCallback(void *response, size_t size, size_t nmemb, void *userp),具有严格的不可修改签名。
    【解决方案4】:

    简单的重载怎么样?

    // in the private section
    static int& do_increase(int& i){ return ++i; }
    static char& do_increase(char& c){
      if(c >= 'a' && c <= 'z')
        c += 'A' - 'a';
      return c;
    }
    template<class U>
    static U& do_increase(U& arg){
      // some default implementation?
      return arg;
    }
    

    (请注意,该标准不保证char 的数值的字母顺序。)

    然后只需在increase 中将其称为return do_increase(element);

    【讨论】:

      【解决方案5】:

      这里通常的解决方案是转发到一个重载的函数 有一个额外的论点。比如:

      template <typename T>
      class MyContainer
      {
          T increase( int const* ) { /* special treatment for int */ }
          T increase( ... )        { /* default treatment         */ }
      public:
          T increase()
          {
              return increase( (T const*)0 );
          }
      };
      

      只要有一点想象力,你就可以想出各种各样的 区别。如果你使用额外的目标函数 参数模板,您甚至可以利用 SFINAE:设计 虚拟参数,以便模板类型替换失败,并且 该函数将不被考虑在重载集中。和 由于所有函数都是内联的,因此很可能存在 只要您进行优化,就不会产生额外的开销。

      【讨论】:

      • 内部increase调用不需要模板参数(实际上会报错)。
      • @Xeo 正确。我最初做了一些更通用的事情,这要求两个目标函数是模板(以便 SFINAE 发挥作用)。我会在这里修复它。
      【解决方案6】:

      这与 Andy Prowls 的回答类似,但都是在编译时使用具有专业化功能的最小辅助类完成的。

      在这种情况下,您有一个实际执行特化的助手,但您也可以让助手类只接受一个布尔值,然后使用 std::is_same&lt;T, int&gt;::value 之类的东西将该值作为模板参数传递。

      template <typename T>
      struct myContainerHelper;
      {
          // General Case
          static inline T increase(T element)
          {
              return ++element;
          }
      };
      
      template <>
      struct myContainerHelper<char>
      {
          // Specific case
          static inline char increase(char element)
          {
              if ((element>='a')&&(element<='z')) element+='A'-'a';
              return element;
          }
      };
      
      template <class T>
      class mycontainer 
      {
          T element;
      public:
          mycontainer (T arg) {element=arg;}
          T increase () 
          {
              return myContainerHelper<T>::increase(element);
          }
      };
      

      这允许您只专门化单个函数而不是整个类。我正在使用带有静态的模板类,因为我已经习惯了 VS2012 对函数模板的部分专业化限制。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        • 1970-01-01
        • 2022-01-20
        • 2019-11-10
        • 1970-01-01
        • 2020-02-08
        • 1970-01-01
        相关资源
        最近更新 更多