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



你好,我对在c++模板类中保留用于计算的值表示怀疑。

场景如下,我们有很多函数,它们在计算中使用一些嵌套计算来设置一些状态/值等。这些嵌套计算对所有这些函数都是重复的。

问题是,在使用模板的情况下,哪种方法是正确的?是否将这些价值观作为成员价值观?或者只是调用内联函数,该函数将就地执行计算?比方说,成员函数/值的值是根据模板参数及其大小计算的,还有一些数学运算,如乘法、减法和除法,通常是我们不想重复的困难数学公式。

具有成员价值的方法:

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_
};

具有成员功能的方法:

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;
}
};

哪种方法在计算效率和代码质量方面更好?调用函数getImportantValueUsedMultipleTime((会返回计算值还是将计算放在使用它的位置?

要回答您提出的问题,似乎在没有优化的情况下,直接调用constexpr函数而不将其存储在static constexpr成员中的版本可以生成更多的代码。这种差异可能会随着优化而消失,但如果您想更加确信,您可以声明函数consteval。请参阅为每个版本生成的代码:https://godbolt.org/z/46xeebbcn

现在,希望能回答你想问的问题。您需要用一些东西初始化static constexpr成员,在您的情况下,可能是一个可以在编译时求值的constexpr函数,将其称为getImporantValueUsedMultipleTimes()。如果该功能取决于";CCD_ 7的类型及其值";,则不能在编译时对其求值,因为val_是一个运行时变量。

你可能正在寻找的解决方案是某种类型的记忆。如果你真的想在编译时完成计算,那么也许可以这样做: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();
}

但这需要您在编译时知道在运行时可能获得的所有可能的参数值(在本例中仅支持0和1(,这是一个很高的要求。更有可能的是,您需要一个在运行时缓存constexpr(注意,不是consteval(computeValue()的结果的系统,并在第二次被要求时返回该结果。如果您知道有一些常用的值,则可以使用这些值的结果初始化缓存,只要您使用文字或constexpr参数,则应在编译时评估computeValue()

当然,有一些开源库可以为您做到这一点,例如https://github.com/jimporter/memo.

最新更新