简体   繁体   English

定义地图数据时的typename,它是一个带有模板的函数指针

[英]typename when defining map data that is a function pointer with a sprinkling of templates

This is a strange question because I already know the 'coding' answer. 这是一个奇怪的问题,因为我已经知道'编码'答案了。 I just want to get a better understanding of why it is so. 我只想更好地理解为什么会如此。 There are guru's here who have a knack of explaining these things better than the C++ standard :) 这里有大师有比C ++标准更好地解释这些东西的诀窍:)

Below we have a means to define an abstract factory template that allocates objects based on a string as a key (it is a contrived example):- 下面我们有一种定义抽象工厂模板的方法,该模板基于字符串作为键来分配对象(这是一个人为的例子): -

#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;

Here is an example of how we use it: - 以下是我们如何使用它的示例: -

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

It will not compile as is, complaining that the map does not have a valid template type argument for the data type. 它不会按原样编译,抱怨地图没有数据类型的有效模板类型参数。 But if you remove the comments around the 'typename' keyword in the static member definition, everything compiles and works fine... why? 但是如果你删除静态成员定义中'typename'关键字周围的注释,一切都编译并正常工作......为什么?

and also, can I make this any better? 而且,我可以做得更好吗? :) :)

The simple reason is that even though you and I looking at the code know that AbstractFactory::MyFactoryConstructor is a type, the compiler doesn't -- or rather, is prohibited by the standard from knowing this. 简单的原因是,即使您和我查看代码知道AbstractFactory :: MyFactoryConstructor是一个类型,编译器也不会 - 或者更确切地说,标准禁止知道这一点。 As far as it knows in the first pass of compilation, MyFactoryConstructor -- itself inside a template yet to be fully realized -- could be something else, like a static variable, which isn't allowed as the second template argument to the map, which requires a type. 据它在编译的第一遍中所知,MyFactoryConstructor - 本身在一个尚未完全实现的模板中 - 可能是其他东西,如静态变量,不允许作为地图的第二个模板参数,这需要一种类型。 Supplying "typename" permits the compiler to treat it as a type as soon as it is first encountered. 提供“typename”允许编译器在第一次遇到它时立即将其视为类型。

The standard tries to allow an implementation to parse and detect as many errors in a template as possible when it reads the template definition, before any instantiations. 在任何实例化之前,标准尝试允许实现在读取模板定义时尽可能多地解析和检测模板中的错误。 C++ is not context independent, however, and it's very difficult, if not impossible, to correctly parse statements if you don't know which symbols are types and which are templates. 但是,C ++不依赖于上下文,如果您不知道哪些符号是类型而哪些是模板,则正确解析语句是非常困难的,如果不是不可能的话。 If the symbol is dependent (depends on the template parameters in some way), you have to tell the compiler when it is a type or a template; 如果符号是依赖的(以某种方式取决于模板参数),则必须告诉编译器它何时是类型或模板; otherwise, the compiler must assume that it is something else. 否则,编译器必须假定它是其他东西。 In this case, you're telling the compiler that AbstractFactory::MyFactoryConstructor names a type, and not something else. 在这种情况下,您告诉编译器AbstractFactory :: MyFactoryConstructor命名一个类型,而不是其他东西。

If, when the template is instantiated, and the compiler can see to what the symbol is really bound, it turns out that you lied (eg AbstractFactory::MyFactoryConstructor is in fact an int), then the compiler will get mad at you. 如果,当模板被实例化,并且编译器可以看到符号实际绑定的内容时,事实证明你撒谎(例如,AbstractFactory :: MyFactoryConstructor实际上是一个int),那么编译器会对你生气。

Note too that the fact that the AbstractFactory was defined before the definition requiring the typedef doesn't change anything. 另请注意,在需要typedef的定义之前定义AbstractFactory的事实不会改变任何内容。 There could always be an explicit specialization for the type you're instantiating AbstractFactory on. 对于您实例化AbstractFactory的类型,可能始终存在明确的特化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM