如何定义C++结构体以用于配置?

huangapple go评论61阅读模式
英文:

How to define C++ struct for configuration?

问题

以下是您要的翻译:

我一直在尝试解决C++中的以下问题。我想要定义一个包含某个软件模块的配置参数的结构体。配置参数基本上是浮点数值,有两种类型:

  • 独立参数,即它们的值直接由一些浮点数提供
  • 依赖参数,即它们的值由一些表达式提供,其中操作数是独立参数

这是一个示例:

struct Configuration {
    float param_independent_01;
    float param_independent_02;
    float param_dependent_01; // param_independent_01 + param_independent_02
    float param_dependent_02; // 1.5f*param_independent_01/(param_independent_01 + param_independent_02)
};

我一直在寻找一种解决方案,使客户端代码只能为独立参数设置值,而依赖参数的值将在幕后自动计算。

Configuration config = {
    param_independent_01 = 0.236f,
    param_independent_02 = 0.728f
    // param_dependent_01 = 0.236f + 0.728f
    // param_dependent_02 = 1.5f*0.236f/(0.236f + 0.728f)
};

我假设Configuration结构将仅被实例化一次,并且参数的值在编译时已知。是否有人可以给我一些建议,如何在C++中实现这一点?

英文:

I have been trying to solve following problem in C++. I would like to define a struct containing a configuration parameters for some software module. The configuration parameters are basically a floating point values and they are of two types:

  • parameters which are independent i.e. their values are given directly by some floating point numbers
  • parameters which are dependent i.e. their values are given by some expressions where the operands are the independent parameters

Here is an example

struct Configuration {
	float param_independent_01;
    float param_independent_02;
	float param_dependent_01; // param_independent_01 + param_independent_02
	float param_dependent_02; // 1.5f*param_independent_01/(param_independent_01 + param_independent_02)
};

I have been looking for a solution which enables the client code to only set values for the independent parameters and the dependent parameters values will be calculated automatically behind the scene.

Configuration config = {
	param_independent_01 = 0.236f,
    param_independent_02 = 0.728f
    // param_dependent_01 = 0.236f + 0.728f
    // param_dependent_02 = 1.5f*0.236f/(0.236f + 0.728f)
};

I suppose that the Configuration structure will be instantiated only once and the values of the parameters are known at compile time. Can anybody give me an advice how to do that in the C++?

答案1

得分: 3

使用C++的构造函数初始化列表来实现这种行为的一种方法是:

struct Configuration {
    float param_independent_01;
    float param_independent_02;
    float param_dependent_01;
    float param_dependent_02;

    Configuration(float p1, float p2) :
        param_independent_01(p1),
        param_independent_02(p2),
        param_dependent_01(p1 + p2),
        param_dependent_02(1.5f * p1 / (p1 + p2))
    {}
};

int main() {
    Configuration config(0.236f, 0.728f);
    return 0;
}

这段代码使用构造函数初始化列表来初始化Configuration结构中的成员变量,以实现所需的行为。

英文:

One approach to achieve this behavior is to make use of C++'s constructor initialization list.

struct Configuration {
    float param_independent_01;
    float param_independent_02;
    float param_dependent_01;
    float param_dependent_02;

    Configuration(float p1, float p2) :
        param_independent_01(p1),
        param_independent_02(p2),
        param_dependent_01(p1 + p2),
        param_dependent_02(1.5f * p1 / (p1 + p2)
        )
    {}
};

int main() {
    Configuration config(0.236f, 0.728f);
    return 0;
}

答案2

得分: 2

只有代码部分,不要翻译:

Or just inline constexpr variables in a namespace (can be put in a header).
This allows you to write some constexpr (consteval) functions to calculate the values too. (Not everything needs to be a class or a struct)

// header file
#pragma once

namespace configuration
{
    inline constexpr float get_param_dependent_02(const float p1, const float p2)
    {
        return (1.5f * p1) / (p1+p2);
    }

    inline constexpr float param_independent_01{ 0.236f };
    inline constexpr float param_independent_02{ 0.728f };
    inline constexpr float param_dependent_01 = param_independent_01 + param_independent_02; // direct
    inline constexpr float param_dependent_02 = get_param_dependent_02(param_independent_01, param_independent_02); // or through constexpr/consteval function
};

int main()
{
    float f = configuration::param_dependent_02;
}
英文:

Or just inline constexpr variables in a namespace (can be put in a header).
This allows you to write some constexpr (consteval) functions to calculate the values too. (Not everything needs to be a class or a struct)

// header file
#pragma once

namespace configuration
{
    inline constexpr float get_param_dependent_02(const float p1, const float p2)
    {
        return (1.5f * p1) / (p1+p2);
    }

    inline constexpr float param_independent_01{ 0.236f };
    inline constexpr float param_independent_02{ 0.728f };
    inline constexpr float param_dependent_01 = param_independent_01 + param_independent_02; // direct
    inline constexpr float param_dependent_02 = get_param_dependent_02(param_independent_01, param_independent_02); // or through constexpr/consteval function
};

int main()
{
    float f = configuration::param_dependent_02;
}

答案3

得分: 1

如果你知道配置不会在运行时更改,可以为 Configuration 实现一个 constexpr 构造函数,然后定义一个 constexpr Configuration 变量。构建将在编译时完成(请参阅下面的godbolt链接生成的汇编代码)。

如果你想确保配置在运行时不会更改,我建议将 Configuration 改为一个具有私有成员的类,然后只提供这些成员的访问器。

还要注意构造函数可能会引发异常(由于除以零)。如果你想控制这种情况,可以在构造函数体中使用 try-catch 来捕获设置依赖参数2的情况。

演示链接

英文:

If you know the configuration is not going to change at runtime, you can implement a constexpr constructor for Configuration, and then define a constexpr Configuration variable. The construction will be done at compile time (see the generated assembler code for the godbolt link below).

If you wanted to make sure the configuration is not going to change at runtime, I would change Configuration into a class with private members, and just provide accessors for those members.

Notice also that the constructor may throw (due to a division by zero). If you want to take control of that situation, you may want to try-catch the setting of the dependent parameter 2 in the constructor's body.

[Demo]

#include <fmt/format.h>
#include <iostream>

class Configuration {
    float param_independent_01;
    float param_independent_02;
    float param_dependent_01;
    float param_dependent_02;
public:
    constexpr Configuration(float p1, float p2)
    : param_independent_01{p1}
    , param_independent_02{p2}
    , param_dependent_01{p1 + p2}
    , param_dependent_02{(p1 * 1.5f)/param_dependent_01}
    {}

    auto get_pi1() { return param_independent_01; }
    auto get_pi2() { return param_independent_02; }
    auto get_pd1() { return param_dependent_01; }
    auto get_pd2() { return param_dependent_02; }

    friend std::ostream& operator<<(std::ostream& os, const Configuration& c) {
        return os << fmt::format("pi1: {}\npi2: {}\npd1: {}\npd2: {}\n",
            c.param_independent_01, c.param_independent_02,
            c.param_dependent_01, c.param_dependent_02);
    }
};

int main() {
    constexpr Configuration c{3.14, 9.8};
    std::cout << c;
}

答案4

得分: 0

不需要使用自定义构造函数的类,只需这样做:

struct Configuration
{
    float param_independent_01 = 0; // 始终初始化所有类成员。
    float param_independent_02 = 0;
    
    float param_dependent_01() const {return param_independent_01 + param_independent_02;}
    float param_dependent_02() const {return 1.5f*param_independent_01/(param_independent_01 + param_independent_02);}
};
英文:

No need for a class with a custom constructor, just do this:

struct Configuration
{
    float param_independent_01 = 0; // Always initialize all class members.
    float param_independent_02 = 0;
    
    float param_dependent_01() const {return param_independent_01 + param_independent_02;}
    float param_dependent_02() const {return 1.5f*param_independent_01/(param_independent_01 + param_independent_02);}
};

huangapple
  • 本文由 发表于 2023年2月8日 22:48:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/75387471.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定