【问题标题】:define constants in a struct在结构中定义常量
【发布时间】:2021-09-27 12:29:45
【问题描述】:

我正在尝试创建一个包含一些常量的结构,如下所示:

#include <CoreAudio/CoreAudio.h>
...
struct properties {
    //Volume control
    const AudioObjectPropertyAddress volume = {
        kAudioDevicePropertyVolumeScalar, //mSelector
        kAudioDevicePropertyScopeOutput, //mScope
        0 //mElement
    };
    //Mute control
    const AudioObjectPropertyAddress mute = { 
        kAudioDevicePropertyMute,
        kAudioDevicePropertyScopeOutput,
        0
    };
};

但是,我无法访问此类中的常量;

//Function used to for example set volume level or set mute status
//bool setProperty(UInt32 data_to_write, AudioObjectPropertyAddress addr_to_write_to);
//Following line should mute the system audio
setProperty(1, properties::mute);

这将使编译器返回以下错误:

error: invalid use of non-static data member 'mute'

所以,我尝试像这样将常量设为静态:

const static AudioObjectPropertyAddress volume = { ...

但是现在,我得到一个不同的错误:

error: in-class initializer for static data member of type 'const AudioObjectPropertyAddress' requires 'constexpr' specifier

我尝试的最后一件事是将const static 更改为static constexpr,但是我再次无法访问常量。每次我尝试访问它们时,编译器都会显示此错误:

Undefined symbols for architecture x86_64:
  "properties::mute", referenced from:
      _main in main-fefb9f.o
ld: symbol(s) not found for architecture x86_64

我不太确定这里发生了什么,我尝试将我的结构转换为一个类,但我最终得到了相同的 Undefined symbols 错误。 我知道我可以将这两个常量定义为全局变量,但我认为将它们放入结构/类中会使代码看起来“更好”或者更有条理。 有人可以解释一下这里出了什么问题并提供可能的解决方案吗?

【问题讨论】:

  • 我相信给静态结构/类成员在其封闭结构/类定义之外的位置的要求来自传统的期望,即结构位于标头内部,因此即使它们的定义也可能在多个“编译单元”。我希望一旦 C++20 模块成为 C++ 库/模块化的主要因素,这个要求最终会被删除。
  • 我在第一个代码块中没有看到静态,因此在转到 constexpr 时它也可能丢失了。某些类在您使用它们的方式上可能与 {} 不兼容 - 例如,如果它们包含联合,则您只能设置一些成员。提供成员是什么或验证您的 ={} 在更简单的上下文中是否按预期工作。

标签: c++ c++11


【解决方案1】:
  •   struct properties {
          //Volume control
          const AudioObjectPropertyAddress volume = {
              kAudioDevicePropertyVolumeScalar, //mSelector
              kAudioDevicePropertyScopeOutput, //mScope
              0 //mElement
          };
      };
    

    有效,但volume不是静态成员,所以使用需要实例:

    setProperty(1, properties{}.volume);
    
  • 使用static const,它将是:

    struct properties {
        //Volume control
        static const AudioObjectPropertyAddress volume;
    };
    
    const properties::AudioObjectPropertyAddress volume {
        kAudioDevicePropertyVolumeScalar, //mSelector
        kAudioDevicePropertyScopeOutput, //mScope
        0 //mElement
    };
    

    并且使用可能是预期的:

    setProperty(1, properties::volume);
    
  • 在 C++11/C++14 中使用 static constexpr

    struct properties {
        //Volume control
        static constexpr AudioObjectPropertyAddress volume{
            kAudioDevicePropertyVolumeScalar, //mSelector
            kAudioDevicePropertyScopeOutput, //mScope
            0 //mElement
        };
    };
    
    const properties::AudioObjectPropertyAddress volume; // Definition when ODR-used
    
  • 从 C++17 开始使用 static /*inline*/ constexpr

    struct properties {
        //Volume control
        static /*inline*/ constexpr AudioObjectPropertyAddress volume{
            kAudioDevicePropertyVolumeScalar, //mSelector
            kAudioDevicePropertyScopeOutput, //mScope
            0 //mElement
        };
    };
    

【讨论】:

    【解决方案2】:

    为什么不只使用 properties.volume 和 properties.mute 或使用命名空间...

    namespace properties 
    {
        //Volume control
        const AudioObjectPropertyAddress volume = {
            kAudioDevicePropertyVolumeScalar, //mSelector
            kAudioDevicePropertyScopeOutput, //mScope
            0 //mElement
        };
    
        //Mute control
        const AudioObjectPropertyAddress mute = { 
            kAudioDevicePropertyMute,
            kAudioDevicePropertyScopeOutput,
            0
        };
    };
    

    【讨论】:

      【解决方案3】:

      以下是您可以尝试的列表:

      您可以....重新设计您的模板/类型。 Struct vs Namespace。如果没有看到整个项目,很难在特定方向上进行指导。由您决定是否需要使用结构、枚举、命名空间、类来封装您的代码。

      至于 const 静态声明。 Here is a post 描述静态类成员声明的有效方法。请密切注意您的 c++ 版本。

      "在 C++11 之前,只有整数的静态 const 数据成员或 枚举类型可以在类定义中有初始化器。”

      最后,静态 constexpr 未定义。您的静态变量与您调用它的位置是否在同一个头文件/源文件中? (可能不是,因为错误显示来自 main 的调用)。 Static variables are not visible to other files.

      如果您想修改静态变量,您可以使用类函数中的公共 get/set 来完成。

      假设“静音”是单个 uint8_t 值。考虑使用将所有静态数据声明为的命名空间:static const uint8_t mute。

      【讨论】:

        猜你喜欢
        • 2015-11-09
        • 2023-03-12
        • 1970-01-01
        • 2011-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-27
        • 1970-01-01
        相关资源
        最近更新 更多