43
// 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 类型做一个单独的整个类 def。

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

如何检查 T 是 int 还是 char?

4

6 回答 6

48

你可以使用typeid

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

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

if (std::is_same<T, int>::value)
于 2013-03-04T10:55:20.990 回答
20

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

但是,如果您只想检查两种类型是否相同,std::is_same<>类型特征应该可以帮助您:

#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<T, int>::value在编译时是已知的。这意味着语句的 the和分支都必须编译truefalseif

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

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在评论中正确指出的那样,编译器可能会发出警告,因为您的条件将始终评估为true或 to false,因此两个分支之一将包含无法访问的代码。

于 2013-03-04T10:55:34.923 回答
17

您可以使用显式模板专业化

#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;
}
于 2016-02-29T07:28:53.543 回答
8

简单的重载怎么样?

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

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

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

于 2013-03-04T10:56:37.400 回答
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:设计虚拟参数,以便模板类型替换失败,并且该函数将不被考虑在重载集中。并且由于所有函数都是内联的,因此很可能不会有额外的开销,前提是您进行了优化。

于 2013-03-04T10:58:43.073 回答
0

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

在这种情况下,您有一个实际执行特化的助手,但您也可以让助手类只接受一个布尔值,然后使用类似的东西std::is_same<T, int>::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 对函数模板的部分专业化的限制。

于 2013-03-05T20:09:48.057 回答