我怎样才能用静态变量 (C++) 干掉这些函数
How can I DRY up these functions with static variables (C++)?
我正在做一个来自欧拉项目的问题,涉及查找三角形、正方形、五边形、...、八角形数字,所以我正在尝试创建这个实用程序来验证每种数字。我决定为每组数字创建筛子以便快速访问,并将其存储在静态数组中。我能够创建一个通用函数来生成每个筛子,但这会使每个验证函数非常相似。由于它们使用静态布尔数组的方式,我没有看到防止在这些函数中重复代码的好方法。你有什么想法可以解决这个问题?
#ifndef FIGURATE_NUMBERS
#define FIGURATE_NUMBERS
#define SIEVE_MAX 10000
void populateFigurateSieve(bool* sieve, const int ADDER_INCREASE)
{
int number = 0;
int adder = 1;
for (int i = 0; i < SIEVE_MAX; i++)
{
if (i == number)
{
sieve[i] = true;
number += adder;
adder += ADDER_INCREASE;
}
else
{
sieve[i] = false;
}
}
return;
}
bool isTriangleNumber(long long int n)
{
static bool triangleNumberSieve[SIEVE_MAX];
static bool initialized = false;
if (!initialized)
{
populateFigurateSieve(triangleNumberSieve, 1);
initialized = true;
}
return triangleNumberSieve[n];
}
bool isSquareNumber(long long int n)
{
static bool squareNumberSieve[SIEVE_MAX];
static bool initialized = false;
if (!initialized)
{
populateFigurateSieve(squareNumberSieve, 2);
initialized = true;
}
return squareNumberSieve[n];
}
bool isPentagonalNumber(long long int n)
{
static bool pentagonalNumberSieve[SIEVE_MAX];
static bool initialized = false;
if (!initialized)
{
populateFigurateSieve(pentagonalNumberSieve, 3);
initialized = true;
}
return pentagonalNumberSieve[n];
}
#endif
我很欣赏你的C方法,但在这里C++人们喜欢类。(-:例如,它们允许您通过抽象常量值来不重复自己。对于三个不同的步骤常量,您有相同的代码:1、2 和 3,因此您可以使用如下所示的内容为它们创建模板:
#include <vector>
constexpr long long SIEVE_MAX = 10000;
template <int ADDER_INCREASE>
class GenericSieve
{
static std::vector<bool> Sieve;
static std::vector<bool> populated_sieve()
{
int number = 0;
int adder = 1;
std::vector<bool> sieve(SIEVE_MAX);
for (int i = 0; i < SIEVE_MAX; i++)
{
if (i == number)
{
sieve[i] = true;
number += adder;
adder += ADDER_INCREASE;
}
else
{
sieve[i] = false;
}
}
return sieve;
}
public:
static bool belongs(long long n)
{
if (Sieve.size() == 0)
{
Sieve = populated_sieve();
}
return Sieve.at(n);
}
};
template<int inc>
std::vector<bool> GenericSieve<inc>::Sieve;
// define a sieve for every number you like
using TriangularSieve = GenericSieve<1>;
using SquareSieve = GenericSieve<2>;
using PentagonalSieve = GenericSieve<3>;
// define functions if you will
bool isTriangleNumber(long long int n)
{
return TriangularSieve::belongs(n);
}
bool isSquareNumber(long long int n)
{
return SquareSieve::belongs(n);
}
bool isPentagonalNumber(long long int n)
{
return PentagonalSieve::belongs(n);
}
如您所见,我主要使用您的代码,但现在它都是模板化类的静态函数。
模板确实是一种分解代码的方法,例如:
template <std::size_t N>
constexpr std::array<bool, N> make_sieve(std::size_t ADDER_INCREASE)
{
std::size_t number = 0;
std::size_t adder = 1;
std::array<bool, N> sieve{};
for (std::size_t i = 0; i < N; i++)
{
if (i == number)
{
sieve[i] = true;
number += adder;
adder += ADDER_INCREASE;
}
else
{
sieve[i] = false;
}
}
return sieve;
}
template <std::size_t N, std::size_t Sieve>
constexpr bool belongs(long long n)
{
constexpr auto sieve = make_sieve<N>(Sieve);
return sieve[n];
}
constexpr std::size_t SIEVE_MAX = 10'000;
constexpr bool isTriangleNumber(long long int n) { return belongs<SIEVE_MAX, 1>(n); }
constexpr bool isSquareNumber(long long int n) { return belongs<SIEVE_MAX, 2>(n); }
constexpr bool isPentagonalNumber(long long int n) { return belongs<SIEVE_MAX, 3>(n); }
演示
(我本来更喜欢std::bitset
,但缺少一些 constexpr 方法:((
(如果你不能使用constexpr
,static const auto sieve = make_sieve<N>(Sieve);
只允许计算一次,没有你的init标志(。
void doInit(bool& initialized, bool* sieve, int adderIncrease) {
if (!initialized) {
populateFigurateSieve(sieve, adderIncrease);
initialized = true;
}
}
然后,使用与之前调用populateFigurateSieve
相同的参数调用它,只是您还在前面传递了 initialized
变量。
通过将初始化检查移动到函数而不是每次重复 90% 的检查,在每个函数中节省 2 行。
遵循 DRY 原则的最佳方法是尝试查看类似的代码有哪些共同点。在这里,我注意到您正在对每个函数执行相同的初始化检查,主要区别在于您如何调用populateFigurateSieve
函数。然后,我通过参数化差异来制作函数,同时保持相似之处的相同一般结构。
编辑:更好的是,你不需要初始化的变量。您可以让它创建并返回一个数组,而不是传递指向填充函数的指针:
#include <array>
// ...
std::array<bool, SIEVE_MAX> populateFigurateSieve(const int ADDER_INCREASE) {
std::array<bool, SIEVE_MAX> sieve {};
// ... (Your code should still work...,)
return sieve;
}
// ...
// When making the sieve in the function:
static std::array<bool, SIEVE_MAX> sieve = populateFigurateSieve( /* Required value here */);
// No longer need initialized variable
// ....
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗