Reputation: 253
I'm trying to create a class that is constructed at compile time and then can be used, of course without any method that modifies it.
I'm new with the keywords static
and constexpr
, so probably I'm not using them properly.
Here is my code:
#include <array>
#include <iostream>
using namespace std;
template<typename unsigned_integer, unsigned_integer max_n>
class ClassicSieve {
private:
static array<bool, max_n+1> prime;
//unsigned_integer max_n;
public:
constexpr ClassicSieve() {
// 1 is not prime
prime[1] = false;
// even numbers
for(unsigned_integer i = 4; i <= max_n; i+=2) {
prime[i] = false;
}
// all the others
for (unsigned_integer p = 3; p*p <= max_n; p++) {
if (prime[p]) {
for(unsigned_integer j = 2*p; j <= max_n; j+=p) {
prime[j] = false;
}
}
}
}
inline bool is_prime(unsigned_integer n) {
return prime[n];
}
};
int main() {
constexpr auto s = ClassicSieve<unsigned int, 10000000>();
cout << s.is_prime(2) << endl;
cout << s.is_prime(3) << endl;
cout << s.is_prime(4) << endl;
cout << s.is_prime(5) << endl;
cout << s.is_prime(6700417) << endl;
}
Once max_n
is fixed all the computation needed can be evaluated at compile-time, so for sure, it can be possible to do what I'm trying.
The method is_prime
just read the data_member prime
without modifying it.
When I compile I get:
note: a constant expression cannot modify an object that is visible outside that expression
referred to the constructor. I see that this is a problem in general, but in my case I won't modify the object anymore. How can I tell it to the compiler?
Upvotes: 0
Views: 1015
Reputation: 41220
There are many issues with this code:
std::array
is uninitialized, and only some values are set to false
afterwards; you need to initialize all values to true
is_prime
const
std::array
attempt to perform stack-allocation, and this will take up a significant amount of thatis_prime
to be inline
; it already is by virtue of being defined in the class declarationHere's an implementation that will do the trick (I've restricted the size to 10 instead of 10 million):
template<typename unsigned_integer, unsigned_integer max_n>
class ClassicSieve {
private:
static constexpr const std::array<bool, max_n+1> prime = ClassicSieve::init_primes();
static constexpr auto init_primes()
{
std::array<bool, max_n+1> prime{};
prime.fill(true);
// 1 is not prime
prime[1] = false;
// even numbers
for(unsigned i = 4; i <= max_n; i+=2) {
prime[i] = false;
}
// all the others
for (unsigned p = 3; p*p <= max_n; p++) {
if (prime[p]) {
for(unsigned j = 2*p; j <= max_n; j+=p) {
prime[j] = false;
}
}
}
return prime;
}
public:
bool is_prime(unsigned_integer n) const {
return prime[n];
}
};
(*This code assumes at least a 32 bit unsigned integer)
Usage:
constexpr auto s = ClassicSieve<unsigned int, 10>();
std::cout << std::boolalpha << s.is_prime(2) << std::endl; // true
std::cout << std::boolalpha << s.is_prime(3) << std::endl; // true
std::cout << std::boolalpha << s.is_prime(4) << std::endl; // false
std::cout << std::boolalpha << s.is_prime(5) << std::endl; // true
Upvotes: 4