Это странный вопрос, потому что я уже знаю ответ «кодирование». Я просто хочу лучше понять, почему это так. Здесь есть гуру, которые умеют объяснять эти вещи лучше, чем стандарт C ++:)
Ниже у нас есть средство для определения абстрактного фабричного шаблона, который выделяет объекты на основе строки в качестве ключа (это надуманный пример): -
#include <iostream>
#include <map>
#include <string>
using namespace std;
template <typename T, typename TProduct>
TProduct *MyFactoryConstructHelper(const T *t)
{
if (!t) return new T;
return new T(*static_cast<const T*>(t));
}
template <typename TProduct>
class AbstractFactory
{
public:
typedef TProduct *(*MyFactoryConstructor)(const void *);
typedef map<string, MyFactoryConstructor> MyFactoryConstructorMap;
static TProduct *Create(const string &iName)
{
MyFactoryConstructor ctr = mTypes[iName];
TProduct *result = NULL;
if(ctr) result = ctr(NULL);
return result;
}
template <typename T>
static bool Register(const string &iName) {
typedef TProduct*(*ConstructPtr)(const T*);
ConstructPtr cPtr = MyFactoryConstructHelper<T, TProduct>;
string name = iName;
mTypes.insert(pair<string,MyFactoryConstructor>(name, reinterpret_cast<MyFactoryConstructor>(cPtr)));
return(true);
}
protected:
AbstractFactory() {}
static MyFactoryConstructorMap mTypes;
};
template <typename TProduct>
map<string, /*typename*/ AbstractFactory<TProduct>::MyFactoryConstructor> AbstractFactory<TProduct>::mTypes;
Вот пример того, как мы его используем: -
class MyProduct
{
public:
virtual ~MyProduct() {}
virtual void Iam() = 0;
};
class MyProductFactory : public AbstractFactory<MyProduct>
{
public:
};
class ProductA : public MyProduct
{
public:
void Iam() { cout << "ProductA" << endl; }
};
class ProductB : public MyProduct
{
public:
void Iam() { cout << "ProductB" << endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
MyProduct *prd;
MyProductFactory::Register<ProductA>("A");
MyProductFactory::Register<ProductB>("B");
prd = MyProductFactory::Create("A");
prd->Iam();
delete prd;
prd = MyProductFactory::Create("B");
prd->Iam();
delete prd;
return 0;
}
Он не будет компилироваться как есть, жалуясь, что на карте нет допустимого аргумента типа шаблона для типа данных. Но если вы удалите комментарии вокруг ключевого слова typename в определении статического члена, все компилируется и работает нормально ... почему?
а также, могу ли я сделать это лучше? :)