成员函数的部分特化

时间:2014-03-21 23:51:37

标签: c++ templates template-specialization

我遇到模板专业化问题。下面是两个类,AbstractSetting(父)和Setting(子)。 (AbstractSetting可能并不重要,但我将其包含在上下文中。)

此代码的最终目标是创建一个容器来保存不同类型的各种INI设置 - 字符串,整数,枚举等(DataType),可以使用枚举(IndexType)引用。在不同的上下文中可能有不同的索引枚举(主游戏,测试套件,服务器等)。

我正在尝试创建一系列fromString方法,当传递一个字符串时,返回一个DataType对象(我的模板参数之一)。

所呈现的代码将编译但不会链接。

如果我取消注释断言,它将链接,但不会调用任何特化,并且无论参数如何,断言都会在每次调用fromString时跳闸。

我该如何使这项工作?

请注意,U32,S32等是整数类型。

template <class IndexType>
class AbstractSetting
{
private:
   IndexType mName;     // Value we use to look this item up
   string mIniKey;      // INI key
   string mIniSection;  // INI section
   string mComment;

public:
   // Constructor
   AbstractSetting(IndexType name, const string &key, 
                   const string &section, const string &comment):
      mIniKey(key), 
      mIniSection(section), 
      mComment(comment)
   {
      mName = name;
   }

   ~AbstractSetting() { /* Do nothing */ }      // Destructor

   IndexType getName()    const { return mName; }
   string    getKey()     const { return mIniKey; }
   string    getSection() const { return mIniSection; }
   string    getComment() const { return mComment; }

   virtual void setValFromString(const string &value) = 0;

   virtual string getValueString() const = 0;         // Returns val as str
   virtual string getDefaultValueString() const = 0;  // Returns def val as str
};


////////////////////////////////////////
////////////////////////////////////////

template <class DataType, class IndexType>
class Setting : public AbstractSetting<IndexType>
{
   typedef AbstractSetting Parent;

private:
   DataType mDefaultValue;
   DataType mValue;

public:
   Setting(IndexType name, const DataType &defaultValue, const string &iniKey, 
           const string &iniSection, const string &comment):
      Parent(name, iniKey, iniSection, comment),
      mDefaultValue(defaultValue),
      mValue(defaultValue)
   {
      // Do nothing
   }


   ~Setting() { /* Do nothing */ }

   // Templated declaration
   DataType fromString(const string &val) ; //{ Assert(false, "Specialize me!"); }

   // Specializations
   template<string *> string             
   fromString(const string &val) { return val; }

   template<S32 *> S32                
   fromString(const string &val) { return atoi(val.c_str()); }

   template<U32 *> 
   U32 fromString(const string &val) { return atoi(val.c_str()); }

   template<U16 *> 
   U16 fromString(const string &val) { return atoi(val.c_str()); }

   template<DisplayMode *> 
   DisplayMode fromString(const string &val) { return stringToDisplayMode(val); }

   template<YesNo *> 
   YesNo fromString(const string &val) { return stringToYesNo(val); }

   template<RelAbs *> 
   RelAbs fromString(const string &val) { return stringToRelAbs(val); }

   template<ColorEntryMode *> 
   ColorEntryMode fromString(const string &val) { return stringToColorEntryMode(val); }

   template<GoalZoneFlashStyle *> 
   GoalZoneFlashStyle fromString(const string &val) { return stringToGoalZoneFlashStyle(val); }

   template<Color *> 
   Color fromString(const string &val) { return Color::iniValToColor(val); }


   void   setValue(const DataType &value)       { mValue = value;                 }

   DataType getValue() const                    { return mValue;                  }
   string getValueString() const                { return toString(mValue);        }
   string getDefaultValueString() const         { return toString(mDefaultValue); }

   void   setValFromString(const string &value) { setValue(fromString(value));    }
};

1 个答案:

答案 0 :(得分:0)

我找到了解决方案!

由于似乎成员函数不能部分专门化,我通过创建一个不使用IndexType参数的新类来解决问题。

class Evaluator
{
public:
  template <class DataType> DataType fromString(const string &val);
};

在.cpp文件中,我添加了:

// Templated default - needs to be overriden
template<class DataType> DataType
Evaluator::fromString(const string &val) { 
    Assert(false, "Specialize me!"); 
    return DataType(); 
}

// Specializations.
// NOTE: All template specializations must be declared in the namespace scope to be
// C++ compliant.  Shame on Visual Studio!
template<> string             
Evaluator::fromString(const string &val) { return val; }

template<> S32                
Evaluator::fromString(const string &val) { return atoi(val.c_str()); }

template<> U32                
Evaluator::fromString(const string &val) { return atoi(val.c_str()); }

template<> U16                
Evaluator::fromString(const string &val) { return atoi(val.c_str()); }

template<> DisplayMode        
Evaluator::fromString(const string &val) { return stringToDisplayMode(val); }

template<> YesNo              
Evaluator::fromString(const string &val) { return stringToYesNo(val); }

template<> RelAbs             
Evaluator::fromString(const string &val) { return stringToRelAbs(val); }

template<> ColorEntryMode     
Evaluator::fromString(const string &val) { return stringToColorEntryMode(val); }

template<> GoalZoneFlashStyle 
Evaluator::fromString(const string &val) { return stringToGoalZoneFlashStyle(val); }

template<> Color              
Evaluator::fromString(const string &val) { return Color::iniValToColor(val); }

然后,在Setting类中,我用这个调用替换了类似的代码块:

DataType fromString(const string &val) { 
    return mEvaluator.fromString<DataType>(val); 
}

这看起来效果很好,并且非常易读。

如果有兴趣的话,完整的代码将在下面的链接中提供,经过更充分的测试和检查。

https://code.google.com/p/bitfighter/source/browse/zap/Settings.h