【问题标题】:typedef of template includes char[][] - works with VS2008 but not gcc模板的 typedef 包括 char[][] - 适用于 VS2008 但不适用于 gcc
【发布时间】:2016-01-22 02:54:47
【问题描述】:

我正在使用一些库代码。 它可以在 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 出现错误:

error: ‘menu_styles’ cannot appear in a constant-expression

我完全同意。 (此外,将const char * 转换为char *)。

我希望 VS2008 只是用 const char * 而不是 menu_styles 编译这个 typedef,但我真的不确定。

我担心 VisualSudio 正在添加某种类似构造函数的代码,因此无论何时使用此 typedef,此 char * 确实指向 menu_styles

使用 GCC 编译时,我可以用什么替换它?

【问题讨论】:

  • extern const char * menu_styles[MENU_COUNT]; 工作吗?
  • 解释 SysEnum 模板的用途。它的第 6 个模板参数期望完成什么。
  • @Sam Varshavchik ~ 我不知道这个模板的用途。它似乎包含一堆关于菜单样式的元信息。模板 class SysEnum [...]
  • 那样的话,恐怕你不明白它是怎么用的,你也无能为力。这种模板使用违反了 C++ 标准。违反 C++ 标准没有解决方法,因为 gcc 旨在成为符合标准的编译器。如果您了解模板在做什么,也许您可​​以找到一种不同的方式来做它正在做的事情,但不知道它应该做什么,很遗憾没有答案。
  • @JJ Hakala - 不。GCC 说“extern”使它成为“无效类型声明”。没有它,我会得到同样的错误。

标签: c++ templates gcc typedef


【解决方案1】:

你的问题归结为编译

extern const char menu_styles[MENU_COUNT][MAX_LEN];

template<const char* pStr> class SysEnum{
  ...
};

typedef SysEnum <???> MenuStyleEnum;

我将模板参数更改为const char*,因为否则您必须放弃 constness,这不是一件好事。基本上问题是??? 应该是什么。

定义char* 模板参数的最常见方法是在某处有一个char[] 变量,它会衰减为char* 让每个人都开心:

extern const char menu_style0[MAX_LEN];
typedef SysEnum <menu_style0> MenuStyleEnum;//compiles...

然而,正如 cmets 中已经指出的那样,该标准不允许我们执行以下任何操作:

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&lt;&lt;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_styleXmenu_styles 中存在相同的信息,这感觉不是一个很好的解决方案。

如果只有来自menu_styles 的值可以作为模板参数,那么声明会更容易:

template<size_t Index> class SysEnum{
    //use menu_styles[index] for pStr
};

typedef SysEnum <0> MenuStyleEnum;

但是,除了存储在menu_styles 之外,您将失去使用值的可能性,并且需要在SysEnum 中进行一些重构。

【讨论】:

  • 感谢您的回答,但最终它遇到了与问题相同的问题。基本上结果是(出于很好的理由)这种声明是无效的,VS2008 不应该允许它。这部分库代码需要为 GCC 重写。
【解决方案2】:

没有办法理解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;

【讨论】:

    【解决方案3】:

    好的,所以我正在回答我自己的问题。

    该类将一个静态字符串数组作为初始化程序传递给模板 typedef。 C++ 标准(目前)不允许这样做。我猜 VS2008 采用了这个编译时常量指针并使用它。它知道它不会改变,所以它起作用了。

    GCC 坚持标准,拒绝。

    但在 VS2008 的辩护中,GCC 版本显示出比 VS2008 更新得多的编译器。

    因此,为了解决这个问题,进行最小的更改(因为它是标准库代码以高昂的费用购买(是的)),我将char *pStr 更改为一个简单的无符号整数。 pStr 最终被传递到继承到 SysEnum 的进一步构造函数中。

    我添加了一个类型代码来标识要使用的 char[][],并修改了以pStr 作为参数的最终构造函数以接受此代码。然后在该构造函数内部使用该代码,这样如果它收到 MENU_STYLES_CODE 那么它应该使用指针menu_styles 进行初始化。我需要为这个模板的所有 typedef 扩展它。

    typedef SysEnum <s_type_t, c_long, no_style, un_style, MAX_LEN, MENU_STYLES_CODE> MenuStyleEnum;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-11
      • 2012-08-20
      • 1970-01-01
      相关资源
      最近更新 更多