C++03中如何为数组指针类型模板参数设置NULL默认值?
问题
我正在开发一个bit-chord类,希望添加通过模板参数传入字符串数组的功能,使类能以人性化格式打印当前状态。提供的代码在C11及以上版本中将模板参数optLabelArray的默认值改为nullptr可正常运行,但在C03中使用0作为默认值时编译报错,尝试过显式转换为const char*[]但无效,请问如何修改代码使其在C++03中编译通过?
代码示例
#include <iostream> template <unsigned int NumBits, const char * optLabelArray[NumBits]=0> class MyBitChordClass { public: MyBitChordClass() {} static const char * GetBitLabel(unsigned int which) {return ((optLabelArray != 0)&&(which < NumBits)) ? optLabelArray[which] : "???";} bool _bits[NumBits]; }; enum { FRUIT_APPLE, FRUIT_BANANA, FRUIT_CHERRY, NUM_FRUITS }; const char * _fruitLabels[] = { "Apple", "Banana", "Cherry" }; int main(int, char **) { MyBitChordClass<NUM_FRUITS> unlabelledFruits; MyBitChordClass<NUM_FRUITS, _fruitLabels> labelledFruits; std::cout << labelledFruits.GetBitLabel(FRUIT_APPLE) << std::endl; return 0; }
编译错误信息
Mac-mini:~ jaf$ g++ foo.cpp foo.cpp:3:69: error: non-type template argument does not refer to any declaration template <unsigned int NumBits, const char * optLabelArray[NumBits]=0> class MyBitChordClass ^ foo.cpp:28:30: note: while checking a default template argument used here MyBitChordClass<NUM_FRUITS> unlabelledFruits; ~~~~~~~~~~~~~~~~~~~~~~~~~~^ foo.cpp:3:46: note: template parameter is declared here template <unsigned int NumBits, const char * optLabelArray[NumBits]=0> class MyBitChordClass ^ 1 error generated.
解决方案
C++03对非类型模板参数的默认值限制更严格,不能直接用0作为数组类型模板参数的默认值,可通过以下两种方式修改:
方法1:将数组模板参数转换为指针类型
把数组类型的模板参数改为指针类型,因为数组名在模板参数中会隐式退化为指针,且C++03允许0作为指针类型的默认值。修改后的类模板定义如下:
#include <iostream> template <unsigned int NumBits, const char* const* optLabelArray = 0> class MyBitChordClass { public: MyBitChordClass() {} static const char * GetBitLabel(unsigned int which) {return ((optLabelArray != 0)&&(which < NumBits)) ? optLabelArray[which] : "???";} bool _bits[NumBits]; }; enum { FRUIT_APPLE, FRUIT_BANANA, FRUIT_CHERRY, NUM_FRUITS }; const char * _fruitLabels[] = { "Apple", "Banana", "Cherry" }; int main(int, char **) { MyBitChordClass<NUM_FRUITS> unlabelledFruits; MyBitChordClass<NUM_FRUITS, _fruitLabels> labelledFruits; std::cout << labelledFruits.GetBitLabel(FRUIT_APPLE) << std::endl; return 0; }
这种方法兼容性最好,原有调用代码无需修改即可正常工作。
方法2:定义全局空数组作为默认值
如果坚持使用数组类型的模板参数,可以定义一个全局空数组作为默认值,同时修改标签判断逻辑:
#include <iostream> const char* _defaultLabels[] = {}; template <unsigned int NumBits, const char * optLabelArray[NumBits] = _defaultLabels> class MyBitChordClass { public: MyBitChordClass() {} static const char * GetBitLabel(unsigned int which) { return ((optLabelArray != _defaultLabels) && (which < NumBits)) ? optLabelArray[which] : "???"; } bool _bits[NumBits]; }; enum { FRUIT_APPLE, FRUIT_BANANA, FRUIT_CHERRY, NUM_FRUITS }; const char * _fruitLabels[] = { "Apple", "Banana", "Cherry" }; int main(int, char **) { MyBitChordClass<NUM_FRUITS> unlabelledFruits; MyBitChordClass<NUM_FRUITS, _fruitLabels> labelledFruits; std::cout << labelledFruits.GetBitLabel(FRUIT_APPLE) << std::endl; return 0; }
注意:部分编译器可能会因默认数组长度与NumBits不匹配发出警告,因此更推荐方法1。
内容的提问来源于stack exchange,提问作者Jeremy Friesner
相关产品推荐
相关产品推荐

