简体   繁体   English

如何在 c++ 模板 class 中保存用于计算的值?

[英]How to hold values used to calculations in c++ template class?

Hello I have doubt about keeping values used to calculation in c++ template class.您好,我怀疑在 c++ 模板 class 中保留用于计算的值。

The scenario is following, we have a plenty of functions which are using some nested calculations in their calculations for setting some states/values etc. Those nested calculations are repetitive for all of those functions.场景如下,我们有很多函数在计算中使用一些嵌套计算来设置一些状态/值等。这些嵌套计算对于所有这些函数都是重复的。

The problem is in which approach is correct, in case of templates?问题是在模板的情况下哪种方法是正确的? Keeping those values as member value?将这些值保留为成员值? Or just calling inline function which will perform calculation inplace?或者只是调用内联 function 它将执行就地计算? Lets say value of that member function/value is calculated based on template argument and its size and there are some mathematical operations like multiplication, subtraction and divivision, generally say difficult mathematics formula which we don't want to repeat.可以说该成员函数/值的值是根据模板参数及其大小计算的,并且有一些数学运算,例如乘法,减法和除法,通常说我们不想重复的困难数学公式。

Approach with member value:具有成员值的方法:

template <typename T>
class ApproachWithMemberValue {
public:
    void firstOperation()
    {
        member_ = (member_ / importantValueUsedMultipleTime_) + something;
    }

    void secondOperation()
    {
        member_ = (1 / (member_ / importantValueUsedMultipleTime_)) * something;
    }

    //And other plenty of functions which uses importantValueUsedMultipleTime_

private:
    T val_;
    size_t member_;
    constexpr size_t importantValueUsedMultipleTime_ = resultOfOperations;
    //Some mathematical computations based on type of val_ and its value but calculated directly in importantValueUsedMultipleTime_
};

Approach with member function:与成员 function 的方法:

template <typename T>
class ApproachWithMemberFunction {
public:
    void firstOperation()
    {
        member_ = (member_ / getImportantValueUsedMultipleTime()) + something;
    }

    void secondOperation()
    {
        member_ = (1 / (member_ / getImportantValueUsedMultipleTime())) * something;
    }

    //And other plenty of functions which uses getImportantValueUsedMultipleTime()

private:
    T val_;
    size_t member_;

    constexpr inline size_t getImportantValueUsedMultipleTime()
    {
        //Some mathematical computations based on type of val_ and its value
        return resultOfOperation;
    }
};

Which approach is better in computation efficiency and code quality?哪种方法在计算效率和代码质量方面更好? Will calling function getImportantValueUsedMultipleTime() return computed value or put calculation in place where it is used?调用 function getImportantValueUsedMultipleTime() 会返回计算值还是将计算放在使用它的地方?

To answer the question you asked, it seems that, without optimizations, the version that calls the constexpr function directly, without storing it in a static constexpr member, can generate more code.要回答您提出的问题,似乎在没有优化的情况下,直接调用constexpr function 而不将其存储在static constexpr成员中的版本可以生成更多代码。 This difference would probably go away with optimizations, but if you want to be extra sure you can declare the function consteval .这种差异可能会通过优化 go 消失,但如果你想更加确定你可以声明 function consteval See the generated code for each version: https://godbolt.org/z/46xeebbcn查看每个版本的生成代码: https://godbolt.org/z/46xeebbcn

Now, to hopefully answer the question you meant to ask.现在,希望能回答你想问的问题。 You need to initialize a static constexpr member with something, in your case presumably a constexpr function that can be evaluated at compile-time, call it getImporantValueUsedMultipleTimes() .您需要使用某些东西初始化static constexpr成员,在您的情况下,大概是可以在编译时评估的constexpr function ,称之为getImporantValueUsedMultipleTimes() If this functions depends on the "type of val_ and its value", then it cannot be evaluated at compile-time, since val_ is a run-time variable.如果此函数取决于“ val_的类型及其值”,则无法在编译时对其进行评估,因为val_是运行时变量。

The solution you are probably looking for is some type of memoization .您可能正在寻找的解决方案是某种类型的记忆 If you really want the computation to be done at compile-time then maybe something like this: https://godbolt.org/z/o7cqzjjbW如果您真的希望在编译时完成计算,那么可能是这样的: https://godbolt.org/z/o7cqzjjbW

template<typename T>
consteval T computeValue(T arg) {
    return arg * 2;
};

template<typename T>
struct MemoizedValues {
    static inline const std::unordered_map<T, T> k_Values{
        {0, computeValue(0)},
        {1, computeValue(1)}};
};

template<typename T>
T getPrecomputedValue(T arg) {
    return MemoizedValues<T>::k_Values.at(arg);
};

template<typename T>
struct UsingMemoizedValues
{
    T foo() {
        return getPrecomputedValue(m_val);
    }

    T m_val;
};

int main() {
    UsingMemoizedValues<int>{}.foo();
}

But this requires that you know at compile-time all the possible argument values that you might get at run-time (in the example only 0 and 1 are supported), which is a tall ask.但这要求您在编译时知道在运行时可能获得的所有可能的参数值(在示例中仅支持 0 和 1),这是一个很高的要求。 More likely you'd need a system that caches the results of a constexpr (note, not consteval ) computeValue() at run-time, and returns that if asked a second time.您更有可能需要一个系统,该系统在运行时缓存constexpr (注意,不是constevalcomputeValue()的结果,并在第二次询问时返回该结果。 If you know that there are some values that are commonly used you could initialize the cache with results for those values, as long as you use literals or constexpr arguments then computeValue() should be evaluated at compile-time.如果您知道有一些常用的值,您可以使用这些值的结果初始化缓存,只要您使用文字或constexpr arguments,那么应该在编译时评估computeValue()

Of course, there are open-source libraries that do this for you, for example https://github.com/jimporter/memo .当然,有一些开源库可以为您执行此操作,例如https://github.com/jimporter/memo

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM