【问题标题】:Combining GCC's typeof() extension with member access将 GCC 的 typeof() 扩展与成员访问相结合
【发布时间】:2013-01-18 03:55:16
【问题描述】:

我正在开发一个通过模板使用静态多态性的 C++ 库。之所以这样设计,是因为目标是具有小堆栈的嵌入式系统,并且通常有利于inline 成员函数以节省堆栈使用量。

将模板用于静态多态意味着事件发射器(通常是设备驱动程序)的类型名称通常长得令人讨厌:

class DeviceThatUsesSPI<class SPI_BUS_TYPE> {

  public:
    class DeviceEvent : public Event<DeviceThatUsesSPI> {};

    // and the rest of the device driver implementation, including
    // the code that emits that event.

}

SomeSpecificGpioBus gpio_bus();
SoftwareSpiBus<typeof(gpio_bus)> spi_bus(&gpio_bus);
DeviceThatUsesSPI<typeof(spi_bus)> device(&spi_bus);

如您所见,我们使用 GCC typeof 扩展运算符来避免重复写出完整的令人讨厌的类型名称 DeviceThatUsesSPI&lt;SoftwareSpiBus&lt;SomeSpecificGpioBus&gt;&gt;。这在我们尝试过的任何地方都像一个魅力,直到今天我试图用它来访问一个代表事件的嵌套类。在我当前的示例中,这是一个模板特化,实现编译时事件处理程序绑定:

template<>
inline void event_handler<typeof(device)::ExampleEvent>(typeof(device) *emitter) {
    // event handler implementation...
}

不过,我也在一个更简单的变量声明示例中尝试过这个:

typeof(device)::ExampleEvent event;

在这两种情况下,G++ 都无法解析表达式并出现语法错误。我认为这是因为在标准 C++ 语法中,除了标识符之外,没有任何情况下 :: 后面跟着任何东西,并且解析器在遇到冒号时无法回溯并将第一部分视为类型。

但是,the GCC manual about typeof 对这个运算符做出以下承诺:

typeof 构造可以在任何可以使用 typedef 名称的地方使用。例如,您可以在声明、强制转换或sizeoftypeof 内部使用它。

如果我用 typedef 替换示例中 typeof 的两种用法,G++ 很高兴:

typedef typeof(device) device_type;

template<>
inline void event_handler<device_type::ExampleEvent>(typeof(device) *emitter) {
    // event handler implementation...
}

device_type::ExampleEvent event;

因此,这进一步加深了我的怀疑,即编译器对我在语义上编写的内容没有问题,但语法不允许我表达它。虽然使用 typedef 间接确实可以让我工作代码,但为了方便这个库的用户,我更愿意找到一种方法来使事件处理程序声明自包含。有没有办法编写typeof 运算符来消除解析歧义,以便我可以使事件声明单行?

【问题讨论】:

  • 在 C++11 中,您可以使用 decltype 代替编译器扩展的 typeof
  • 如果我的解决方案有效,请告诉我。如果没有,那我就删了。

标签: c++ gcc template-specialization typeof


【解决方案1】:

我认为一个小的元函数可以解决问题。

template<typename T>
struct self
{
   typedef T type;
};

然后将其用作:

template<>
inline void 
event_handler<self<typeof(device)>::type::ExampleEvent>(typeof(device) *emitter)
{
    // event handler implementation...
}

或者您可以将元函数(less 通用)定义为:

template<typename T>
struct event
{
   typedef typename T::ExampleEvent type;
};

然后将其用作:

template<>
inline void 
event_handler<event<typeof(device)>::type>(typeof(device) *emitter)
{
    // event handler implementation...
}

顺便说一句,在 C++11 中,您可以使用 decltype 代替 typeof(这是一个编译器扩展):

template<>
inline void 
event_handler<decltype(device)::ExampleEvent>(typeof(device) *emitter) 
{
    // event handler implementation...
}

希望对您有所帮助。 :-)

【讨论】:

  • 啊,是的,我一开始没有注意到你的评论。这个技巧允许我为旧版本的 GCC 添加 shim,但我还发现,从 GCC 4.7 开始,typeof 或 decltype 都不需要这个技巧。我在第二个答案中记录了我学到的东西,但是您的答案绝对是对如何解决此解析器错误的问题的更直接的答案。谢谢!
【解决方案2】:

根据a bug report against GCC,这是一个已知问题,已在 GCC 4.7 中修复。升级 GCC 是长久之计。

错误报告描述了在旧版本中使用类模板作为间接绕过解析器的进一步解决方法:

class SameType<T> {
  public:
    typedef T R;
}
T<typeof(device)>::ExampleEvent event;

这比 typedef 更好,因为它可以泛化到所有事件类型,但对用户来说仍然不自然。

同样的问题,适用于新标准 decltype 运算符,实际上是 a C++11 specification change 的主题,它阐明了围绕类型解析的规则以使其按预期工作。

【讨论】:

    猜你喜欢
    • 2019-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多