2

如果我想制作一个模板类,并且根据模板参数的 typeid 执行不同的操作,那么我该如何编码呢?

例如,我有以下模板类,我想在其中初始化成员字段数据,具体取决于它是 int 还是 string。

#include <string>

template <class T>
class A
{
private:
    T data;
public:
    A();
};

// Implementation of constructor
template <class T>
A<T>::A()
{
    if (typeid(T) == typeid(int))
    {
        data = 1;
    }
    else if (typeid(T) == typeid(std::string))
    {
        data = "one";
    }
    else
    {
        throw runtime_error("Choose type int or string");
    }
}

但是,此代码无法使用以下主文件进行编译。

#include "stdafx.h"
#include "A.h"
#include <string>

int _tmain(int argc, _TCHAR* argv[])
{
    A<int> one;
    return 0;
}

错误是:error C2440: '=' : cannot convert from 'const char [2]' to 'int',这意味着代码实际上正在检查 else-if 语句中的 int,即使它永远无法到达代码的那部分。

接下来,按照这个例子(根据模板变量类型执行不同的方法),我尝试了下面的 Ah 文件,但是我得到了几个链接器错误,提到 A(void) 已经在 A.obj 中定义。

#include <string>

template <class T>
class A
{
private:
    T data;
public:
    A();
    ~A();
};

// Implementation of constructor
template <>
A<int>::A()
{
    data = 1;
}
template <>
A<std::string>::A()
{
    data = "one";
}

有人知道如何启动并运行此代码吗?我还意识到在模板类中使用这样的 if-else 语句可能会削弱模板的力量。有没有更好的编码方法?

编辑:与 Torsten(下)讨论后,我现在有以下 Ah 文件:

#pragma once

#include <string>

// Class definition
template <class T>
class A
{
public:
    A();
    ~A();
private:
    T data;
};

// Implementation of initialization
template < class T > 
struct initial_data
{
  static T data() { throw runtime_error("Choose type int or string"); }
};

template <> 
struct initial_data< int >
{
    static int data() { return 1; }
};

template <> 
struct initial_data< std::string >
{
    static std::string data() { return "one"; }
};

// Definition of constructor
template <class T>
A<T>::A()
  : data( initial_data< T >::data() ) 
{
}

以及以下主要内容:

#include "stdafx.h"
#include "A.h"
#include <string>

int _tmain(int argc, _TCHAR* argv[])
{
    A<int> ione;

    return 0;
}

我现在得到的链接器错误是:Test template 4.obj : error LNK2019: unresolved external symbol "public: __thiscall A::~A(void)" (??1?$A@H@@QAE@XZ) referenced in函数_wmain

4

3 回答 3

3

明确的专业化是要走的路。

我假设您将 Ah 包含在几个 .cpp 中,这就是您的问题的根本原因。

专业化是定义,A::A() 和 A::A() 必须只有一个定义,因此它们只能在一个 .cpp 中。

您必须在 .cpp 中移动显式专业化

template <>
A<int>::A()
{
    data = 1;
}
template <>
A<std::string>::A()
{
    data = "one";
}

并在 Ah 中为他们保留一份声明

template<> A<int>::A();
template<> A<std::string>::A();

这样编译器就知道它们是明确专门化的,并且不会尝试添加自动的。

编辑:对于这四个文件, g++ m.cpp f.cpp a.cpp 没有显示任何错误。

// a.h
#define A_H

#include <string>

template <class T>
class A
{
private:
    T data;
public:
    A();
};

template<> A<int>::A();
template<> A<std::string>::A();

#endif

// a.cpp
#include "a.h"

template <>
A<int>::A()
{
    data = 1;
}
template <>
A<std::string>::A()
{
    data = "one";
}

// f.cpp
#include "a.h"

int f()
{
    A<int> one;
    A<std::string> two;
}

// m.cpp
#include "a.h"

int f();

int main()
{
    A<int> one;
    A<std::string> two;
    f();
}
于 2012-07-04T09:10:14.567 回答
3

您在第二个解决方案中是正确的,您需要的是模板专业化(将声明和实现放在一起):

#include <string>

template <class T>
class A
{
private:
    T data;
public:
    A();
    ~A();
};

template <>
class A <std::string>
{
private:
  std::string data;
public:
  A() { data = "one"; }
};

template <>
class A <int>
{
private:
  int data;
public:
  A() { data = 1; }
};

如果我可以建议一个更优雅的解决方案,那么我会向构造函数添加一个参数并避免模板专业化:

template <class T>
class A
{
private:
    T data;
public:
    A( T value ) : data( value ) {}
    virtual ~A() {}
};
于 2012-07-04T09:13:13.930 回答
2

如果它只是你想要的行为依赖于 T 的 c'tor,我建议将其分解为不同的结构:

template < class T > 
struct initial_data
{
  static T data() { throw runtime_error("Choose type int or string"); }
};

template <> 
struct initial_data< int >
{
    static int data() { return 1; }
}

template <> 
struct initial_data< std::string >
{
    static std::string data() { return "1"; }
}

如果您在其模板参数上专门化一个类,则不同的专门化是完全不同的类型,并且可以具有不同的数据和功能集。

最后:

template <class T>
A<T>::A()
  : data( initial_data< T >::data() ) 
{
}

亲切的问候托尔斯滕

于 2012-07-04T09:11:41.013 回答