Haa*_*hii 3 c++ templates constexpr c++20
我正在寻找一种方便的方法来创建一个C++
类,其中某些成员变量仅在设置了模板标志时才存在。作为一个简单的例子,我们假设我想在性能敏感的计算中切换averageSum,即
struct Foo {
// Some data and functions..
void operator+=(const Foo& _other) {}
};
template<bool sumAverages>
class Calculator {
public:
// Some member variables...
// Those should only be present if sumAverages is true
int count = 0;
Foo resultSum;
void calculate(/* some arguments */) {
// Calculation of result...
Foo result;
// This should only be calculated if sumAverages is true
++count;
resultSum += result;
// Possibly some post processing...
}
};
Run Code Online (Sandbox Code Playgroud)
一种方法是使用预处理器定义,但这些相当不方便,特别是如果我需要同一二进制文件中的两个版本。所以我正在寻找使用模板和if constexpr
类似以下Conditional
类的替代方案:
template<bool active, class T>
struct Conditional;
template<class T>
struct Conditional<true, T> : public T {};
template<class T>
struct Conditional<false, T> {};
Run Code Online (Sandbox Code Playgroud)
我的第一枪是这样的:
template<bool sumAverages>
class Calculator {
public:
int count = 0;
Conditional<sumAverages, Foo> resultSum;
void calculate(/* some arguments */) {
Foo result;
if constexpr(sumAverages) {
++count;
resultSum += result;
}
}
};
Run Code Online (Sandbox Code Playgroud)
应该if constexpr
不会产生运行时成本,并且因为它依赖于模板变量,所以应该允许在false
这种情况下使用非编译代码(例如,在本例中Conditional<false, Foo>
没有定义+=
运算符,但它仍然可以编译)。所以这部分或多或少是比较完美的。然而,变数count
仍然resultSum
存在。特别是,由于无法从基本类型派生,因此该类Conditional
不允许切换int
对模板的依赖。此外,每个Conditional<false, T>
变量仍然占用一个字节,可能会使小类膨胀。这可以通过新[[no_unique_address]]
属性来解决,但是我当前的编译器选择在所有测试中忽略它,每个变量仍然至少使用一个字节。
为了改进我尝试继承这样的变量
struct OptionalMembers {
int count;
Foo resultSum;
};
template<bool sumAverages>
class Calculator : public Conditional<sumAverages, OptionalMembers> {
public:
void calculate(/* some arguments */) {
Foo result;
if constexpr(sumAverages) {
++OptionalMembers::count;
OptionalMembers::resultSum += result;
}
}
};
Run Code Online (Sandbox Code Playgroud)
这应该没有空间成本,因为从空类继承实际上什么也不做,对吗?一个可能的缺点是不能自由设置变量的顺序(继承的变量总是排在第一位)。
我的问题是:
使用上述方法您是否发现任何问题?
是否有更好的选择来取消(激活)这样的变量?
有多种方法可以解决这个问题,一种简单的方法是使用模板专门化:
#include <iostream>
template <bool b> struct Calculator {
int calculate(int i, int j) { return i + j; }
};
template <> struct Calculator<true> {
int sum;
int calculate(int i, int j) { return sum = i + j; }
};
int main(int argc, char **argv) {
Calculator<false> cx;
cx.calculate(3, 4);
/* std::cout << cx.sum << '\n'; <- will not compile */
Calculator<true> cy;
cy.calculate(3, 4);
std::cout << cy.sum << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
另一个解决方案是使用类似 mixin 的类型来向计算器类型添加功能:
#include <iostream>
#include <type_traits>
struct SumMixin {
int sum;
};
template <typename... Mixins> struct Calculator : public Mixins... {
int calculate(int i, int j) {
if constexpr (is_deriving_from<SumMixin>()) {
return SumMixin::sum = i + j;
} else {
return i + j;
}
}
private:
template <typename Mixin> static constexpr bool is_deriving_from() {
return std::disjunction_v<std::is_same<Mixin, Mixins>...>;
}
};
int main(int argc, char **argv) {
Calculator<> cx;
cx.calculate(3, 4);
/* std::cout << cx.sum << '\n'; <- will not compile */
Calculator<SumMixin> cy;
cy.calculate(3, 4);
std::cout << cy.sum << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
128 次 |
最近记录: |