我有一些我正在使用的库代码。 它在Visual Studio(2008)下编译和工作,但不是GCC(v4.8.4。)
在标题中我们有:
extern const char menu_styles[MENU_COUNT][MAX_LEN];
typedef SysEnum <s_type_t, c_long, no_style, un_style, MAX_LEN, (char *)&menu_styles> MenuStyleEnum;
SysEnum(在另一个文件中定义):
template<class ETYPE, class BTYPE, int MINV, int MAXV, int MLEN, char* pStr> class SysEnum
gcc borks错误:
error: ‘menu_styles’ cannot appear in a constant-expression
我完全赞同。 (此外,它const char *
投射到char *
)。
我希望VS2008只使用const char *
代替menu_styles
编译此typedef,但我真的不确定。
我担心VisualSudio会添加某种类似构造函数的代码,因此只要使用此typedef,此char *
确实指向menu_styles
。
在使用GCC进行编译时,我可以将其更换出来?
答案 0 :(得分:1)
你的问题归结为编译
extern const char menu_styles[MENU_COUNT][MAX_LEN];
template<const char* pStr> class SysEnum{
...
};
typedef SysEnum <???> MenuStyleEnum;
我将模板参数更改为const char*
,因为否则你必须抛弃常量,这不是很好的事情。基本上问题是???
应该是什么。
定义char*
模板参数的最常用方法是在某处设置char[]
变量,这会变为char*
让每个人都满意:
extern const char menu_style0[MAX_LEN];
typedef SysEnum <menu_style0> MenuStyleEnum;//compiles...
但是,正如评论中已经指出的那样,该标准不允许我们执行以下任何操作:
typedef SysEnum <menu_styles[0]> MenuStyleEnum;
typedef SysEnum <*menu_styles> MenuStyleEnum;
typedef SysEnum <static_cast<const char *>(&menu_styles)> MenuStyleEnum;
我不确定技术限制是否是这种行为的原因,毕竟在编译期间可以找出menu_styles[0]
的地址(并且VS就是这样)。我的猜测是它不会编译,因为标准是这样说的。
这不会让你有很多选择。如果SysEnum
仅使用pStr
所指向的值(代码如cout<<pStr
),并且地址本身并不重要(对于像pStr==otherCharPointer
这样的代码就是这种情况),比以下解决方法可能是:
#define _MENU_STYLE0_ "STYLE0"
...
extern const char menu_style0[MAX_LEN]= _MENU_STYLE0_;
...
extern const char menu_styles[MENU_COUNT][MAX_LEN]={ _MENU_STYLE0_, _MENU_STYLE1_, ...};
...
typedef SysEnum <menu_style0> MenuStyleEnum;//compiles!
缺点是,menu_styleX
和menu_styles
中存在相同的信息,这不是一个很好的解决方案。
如果只有来自menu_styles
的值可以作为模板参数,则可能更容易声明:
template<size_t Index> class SysEnum{
//use menu_styles[index] for pStr
};
typedef SysEnum <0> MenuStyleEnum;
但是,除了存储在menu_styles
中之外,您将失去使用值的可能性,并且需要在SysEnum
中进行一些重构。
答案 1 :(得分:0)
无法理解SysEnum
模板。您需要了解menu_styles
参数的使用方式。
然后你需要以合理的方式修补库代码,例如
constexpr const char menu_styles[] = "sample";
template <class ETYPE,
class BTYPE,
int MINV,
int MAXV,
int MLEN,
const char* pStr>
class SysEnum;
typedef SysEnum<s_type_t, c_long, no_style, un_style, MAX_LEN, menu_styles>
MenuStyleEnum;
答案 2 :(得分:0)
Ok, so I'm answering my own question.
The class passes a static array of strings as an initialiser to the template typedef. The C++ standard (at the moment) does not allow this. I guess VS2008 takes this compile-time constant pointer and uses it anyway. It knows it's not going to change, so it works.
GCC sticks to the standard, refusing.
But in VS2008's defence the GCC version shows a much newer compiler than VS2008.
So to code around the issue, making minimal changes (since it's standard library code purchased at great expense (yes really)), I changed the char *pStr
to be a simple unsigned integer. The pStr
was eventually passed down into further constructors inherited into SysEnum.
I added a type-code to identify the char[][] to be used, and modified the final constructor that took pStr
as a parameter to accept this code. Then internal to that constructor it uses that code, such that if it received MENU_STYLES_CODE then it should initialise with the pointer menu_styles
. I need to extend this for all the typedefs of this template.
typedef SysEnum <s_type_t, c_long, no_style, un_style, MAX_LEN, MENU_STYLES_CODE> MenuStyleEnum;