如果我想创建一个模板类,并且根据模板参数的typeid执行不同的操作,那么我该如何编写代码?
例如,我有以下模板类,我想根据它是int还是字符串来初始化成员字段数据。
#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;
}
错误是:错误C2440:'=':无法从'const char [2]'转换为'int',这意味着代码实际上正在检查int的else-if语句,即使它永远不会能够达到代码的那一部分。
接下来,按照这个例子(Perform different methods based on template variable type),我尝试了以下A.h文件,但是我收到了几个链接器错误,提到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语句可能会从模板中删除功能。有没有更好的方法来编码呢?
编辑:在与托尔斯滕(下文)讨论后,我现在有以下A.h文件:#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;
}
我现在得到的链接器错误是:测试模板4.obj:错误LNK2019:未解析的外部符号“public:__thiscall A :: ~A(void)”(?? 1?$ A @ H @@ QAE @ XZ )在函数_wmain中引用
答案 0 :(得分:3)
明确的专业化是要走的路。
我假设您将A.h包含在几个.cpp中,这就是问题的根本原因。
专业化是定义,A :: A()和A :: A()必须只有一个定义,因此它们必须只有一个.cpp。
您必须在.cpp
中移动显式特化template <>
A<int>::A()
{
data = 1;
}
template <>
A<std::string>::A()
{
data = "one";
}
并在A.h
中为他们保留声明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();
}
答案 1 :(得分: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() )
{
}
亲切的问候
托
答案 2 :(得分:2)
你在第二个解决方案中是正确的,你需要的是模板专业化(保持声明和实现在一起):
#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() {}
};