Related
I have two functions, which are identical except for one constant array value. A ternary statement does the job but conceptually nothing is 'conditional' on anything; they're two different functions! This doesn't extend well to when there are more than two variants of a function because if scopes variables so you can't set them to const.
inline int function(const bool the_diagonal_version) {
// do something
const int orthogonal[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
const int diagonal[4][2] = {{1,1},{1,-1},{-1,1},{-1,-1}};
const auto directions = the_diagonal_version?diagonal:orthogonal;
// use these directions, maybe even in a function that overloads/enable_ifs for const/non-const.
return 0;
}
Is there some clever trick with the newfangled constexpr if ? Alternatively is there some hellscape SFINAE solution that at least helps me avoid duplicating code?
You're making a mountain out of a molehill
int function(bool value)
{
const int data[2][4][2] = {{{1,0},{-1,0},{0,1},{0,-1}},
{{1,1},{1,-1},{-1,1},{-1,-1}}
};
const int (&directions)[4][2] = data[value];
// whatever, using directions
}
Optionally, data can be static if desired. This solution has no duplication of code, can be extended as desired to any integral type (with appropriate range checking if needed).
Alternatives might be
int function_internal(const int (&directions)[4][2])
{
// whatever, using directions
}
int function(bool value)
{
const int data[2][4][2] = {{{1,0},{-1,0},{0,1},{0,-1}},
{{1,1},{1,-1},{-1,1},{-1,-1}}
};
const int (&directions)[4][2] = data[value];
return function_internal(directions);
}
or even
int function(bool value)
{
const int data[2][4][2] = {{{1,0},{-1,0},{0,1},{0,-1}},
{{1,1},{1,-1},{-1,1},{-1,-1}}
};
return function_internal(data[value]);
}
or, as a template (which I consider to be over-kill)
template<bool value> int function();
template<> int function<false>()
{
return function_internal({{1,0},{-1,0},{0,1},{0,-1}});
}
template<> int function<true>()
{
return function_internal({1,1},{1,-1},{-1,1},{-1,-1}});
}
// call as function<true>();
Just have the parameter as a template?
template<bool the_diagonal_version>
constexpr int function() {
// do something
const int orthogonal[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
const int diagonal[4][2] = {{1,1},{1,-1},{-1,1},{-1,-1}};
const auto directions = the_diagonal_version?diagonal:orthogonal;
// use these directions, maybe even in a function that overloads/enable_ifs for const/non-const.
return 0;
}
So in a class, I have an array like so:
public:
int playGrid[10][10];//size of the grid, 10x10 or 100 squares
And when I do:
for (int i = iX1; i < iX2; i++)
{
if (i == iX1)
{
playGrid[i][iY1] = 4;
}
}
This:
playGrid[i][iY1] = 4;
gives me:
expression must be a modifiable lvalue
I'm not sure what I'm doing wrong here. This code is inside one of the methods for the class, so it has access to it. I've looked all over the place, but I was unable to find an example where they were using 2D arrays with a simple integer assignment.
Thank you for your help!
EDIT: More code was requested, so here we go:
void Grid::placeBoat(int iX1, int iY1, int iX2, int iY2) const
{
if (iX1 != iX2)
{
if (iX1 < iX2)
{
for (int i = iX1; i < iX2; i++)
{
if (i == iX1)
{
playGrid[i][iY1] = 4;
}
}
}
else
{
}
}
else if (iY1 != iY2)
{
}
}
and here is the grid class:
class Grid
{
public:
int playGrid[10][10];//size of the grid, 10x10 or 100 squares
void drawGrid() const;
void placeBoat(int, int, int, int) const;
Grid();
~Grid();
};
void Grid::placeBoat(int iX1, int iY1, int iX2, int iY2) const
See the const at the end of the definition? It means that you are allow calling this method when the instance (Grid) is constant.
Since you allow that call, the entire function body is compiled assuming that this is of type const Grid *.
You are then trying to change the array, which is a member of the (const) Grid, and hence the compiler error.
The problem is that in a method that is const you are trying to modify the object. Remove the const
class Grid
{
...
void placeBoat(int, int, int, int);
...
};
void Grid::placeBoat(int iX1, int iY1, int iX2, int iY2)
{
...
}
I have a class that needs to use some big arrays, initialized via some complex functions, that will be the same for every instance and will only be read after initialization.
I searched on SO and found some answers on initializing static arrays like this:
char A::a[6] = {1,2,3,4,5,6};
But in my case I need to calculate the arrays at runtime via some function.
(How) can I do it?
Re
” will be the same for every instance and will only be read after initialization
Producing a value is the job of a function.
Just define a function that returns the data you need.
You can use it to initialize a static data member (or whatever). For a header only module, if that's relevant, you will need to employ solution to the "inline data" problem, e.g. a Meyers' singleton (a function that returns a reference to a local static variable). Like this:
#include <vector>
namespace my {
using std::vector;
inline
auto squares()
-> vector<int>
{
vector<int> result;
for( int i = 1; i <= 12; ++i ) { result.push_back( i*i ); }
return result;
}
class A
{
private:
static
auto a()
-> const vector<int>&
{
static const vector<int> the_values = squares();
return the_values;
}
public:
A(){}
};
} // namespace my
You can't use {} sintaxis in execution time, you can use a method:
class A
{
static vector<char> a;
//...
public:
static void initStatic();
}
void A::initStatic()
{
a.resize( /*put the size here... */);
for (auto& x : a)
x = //something...
}
vector reference: http://en.cppreference.com/w/cpp/container/vector
If you aren't using vectors, this works. The reason I let A::initialize do the work, rather than just calling one of these externally defined functions, is that we can and should expect the data member a to be private.
//Declare a function pointer type, so you can pass it into A's
//an initialization function takes in the array and its size
typedef void (*initFunction) (char A[], int arraySize);
//see http://www.cprogramming.com/tutorial/function-pointers.html
// for more on function pointers
class A
{
public:
void initialize (initFunction myInitFunction);
...
private:
char a[ARRAYSIZE];
};
void A::initialize (initFunction myInitFunction)
{
(*myInitFunction) (a, ARRAYSIZE);
}
...
A myA;
myA.initialize (yourArrayInitializingFunction);
Or maybe your initialization functions don't take in arrays and initialize them, but return arrays:
class A
{
public:
void initialize (const char* aInit);
...
};
void A::initialize (const char* aInit)
{
for (int i = 0; i < ARRAYSIZE: ++i)
a[i] = aInit[i];
}
...
A myA;
myA.initialize (yourArrayReturningFunction ());
If you're using vectors, code is simpler:
class A
{
public:
void initialize (const vector<char>& aInit) { a = aInit; }
...
private:
vector<char> a;
};
My suggestion:
Instead of using a static member variable, use a static member function to provide access to the array.
In the static member function, create a static function variable that can be populated the first time it is needed.
Here's what I am thinking of:
char* A::getArray()
{
static char a[6] = {0};
static bool inited = false;
if ( !inited )
{
// Initialize the array elements
a[0] = ... ;
...
a[5] = ... ;
inited = true;
}
return a;
}
Since C++11, one can initialize static const built-in types inside a class definition, like so:
class A {
public:
static const unsigned int val = 0; //allowed
};
However, doing this in Visual C++ 2013 with an array gives me an error telling me that this is not allowed:
class B {
public:
static const unsigned int val[][2] = { { 0, 1 } }; //not allowed
};
The error message simply reads "a member of type const unsigned int [][2] cannot have an in-class initializer." Instead, I'm forced to do the following:
class C {
public:
static const unsigned int val[][2];
};
const unsigned int C::val[][2] = { { 0, 1 } };
This is unfortunate because I have code which relies on the size of val, and I want to be able to change the contents of val without having to remember to go back and change a constant somewhere. Is there a different way of doing this that allows me to use sizeof on val from any point in the file below the declaration?
Your array must be a constexpr (clang and gcc specify it in their error messages) :
class B {
public:
static constexpr const unsigned int val[][2] = { { 0, 1 } };
// ^^^^^^^^
};
See it working here.
Visual Studio CTP 2013 (a "beta" version, that should be avoided for production) provides support for constepxr, which should be available in future releases, too.
EDIT :
If your compiler does not support constexpr (hopefully for you, not for too long), then you cant do in-class initialization of your static array, and must do the old way :
class C {
public:
static const unsigned int val[][2];
};
const unsigned int C::val[][2] = { { 0, 1 } };
If your array type is complete (if you declare all the array dimensions), then sizeof can be applied (the compiler knows how many elements to expect) :
;
class C {
public:
static const unsigned int val[2][2]; // Specify all dimensions.
void foo() { cout << sizeof(C::val); } // OK
};
const unsigned int C::val[][2] = { { 0, 1 } , { 2, 3 } };
int main() {
C c;
c.foo();
return 0;
}
I have the following class in C++:
class a {
const int b[2];
// other stuff follows
// and here's the constructor
a(void);
}
The question is, how do I initialize b in the initialization list, given that I can't initialize it inside the body of the function of the constructor, because b is const?
This doesn't work:
a::a(void) :
b([2,3])
{
// other initialization stuff
}
Edit: The case in point is when I can have different values for b for different instances, but the values are known to be constant for the lifetime of the instance.
With C++11 the answer to this question has now changed and you can in fact do:
struct a {
const int b[2];
// other bits follow
// and here's the constructor
a();
};
a::a() :
b{2,3}
{
// other constructor work
}
int main() {
a a;
}
Like the others said, ISO C++ doesn't support that. But you can workaround it. Just use std::vector instead.
int* a = new int[N];
// fill a
class C {
const std::vector<int> v;
public:
C():v(a, a+N) {}
};
It is not possible in the current standard. I believe you'll be able to do this in C++0x using initializer lists (see A Brief Look at C++0x, by Bjarne Stroustrup, for more information about initializer lists and other nice C++0x features).
std::vector uses the heap. Geez, what a waste that would be just for the sake of a const sanity-check. The point of std::vector is dynamic growth at run-time, not any old syntax checking that should be done at compile-time. If you're not going to grow then create a class to wrap a normal array.
#include <stdio.h>
template <class Type, size_t MaxLength>
class ConstFixedSizeArrayFiller {
private:
size_t length;
public:
ConstFixedSizeArrayFiller() : length(0) {
}
virtual ~ConstFixedSizeArrayFiller() {
}
virtual void Fill(Type *array) = 0;
protected:
void add_element(Type *array, const Type & element)
{
if(length >= MaxLength) {
// todo: throw more appropriate out-of-bounds exception
throw 0;
}
array[length] = element;
length++;
}
};
template <class Type, size_t Length>
class ConstFixedSizeArray {
private:
Type array[Length];
public:
explicit ConstFixedSizeArray(
ConstFixedSizeArrayFiller<Type, Length> & filler
) {
filler.Fill(array);
}
const Type *Array() const {
return array;
}
size_t ArrayLength() const {
return Length;
}
};
class a {
private:
class b_filler : public ConstFixedSizeArrayFiller<int, 2> {
public:
virtual ~b_filler() {
}
virtual void Fill(int *array) {
add_element(array, 87);
add_element(array, 96);
}
};
const ConstFixedSizeArray<int, 2> b;
public:
a(void) : b(b_filler()) {
}
void print_items() {
size_t i;
for(i = 0; i < b.ArrayLength(); i++)
{
printf("%d\n", b.Array()[i]);
}
}
};
int main()
{
a x;
x.print_items();
return 0;
}
ConstFixedSizeArrayFiller and ConstFixedSizeArray are reusable.
The first allows run-time bounds checking while initializing the array (same as a vector might), which can later become const after this initialization.
The second allows the array to be allocated inside another object, which could be on the heap or simply the stack if that's where the object is. There's no waste of time allocating from the heap. It also performs compile-time const checking on the array.
b_filler is a tiny private class to provide the initialization values. The size of the array is checked at compile-time with the template arguments, so there's no chance of going out of bounds.
I'm sure there are more exotic ways to modify this. This is an initial stab. I think you can pretty much make up for any of the compiler's shortcoming with classes.
ISO standard C++ doesn't let you do this. If it did, the syntax would probably be:
a::a(void) :
b({2,3})
{
// other initialization stuff
}
Or something along those lines. From your question it actually sounds like what you want is a constant class (aka static) member that is the array. C++ does let you do this. Like so:
#include <iostream>
class A
{
public:
A();
static const int a[2];
};
const int A::a[2] = {0, 1};
A::A()
{
}
int main (int argc, char * const argv[])
{
std::cout << "A::a => " << A::a[0] << ", " << A::a[1] << "\n";
return 0;
}
The output being:
A::a => 0, 1
Now of course since this is a static class member it is the same for every instance of class A. If that is not what you want, ie you want each instance of A to have different element values in the array a then you're making the mistake of trying to make the array const to begin with. You should just be doing this:
#include <iostream>
class A
{
public:
A();
int a[2];
};
A::A()
{
a[0] = 9; // or some calculation
a[1] = 10; // or some calculation
}
int main (int argc, char * const argv[])
{
A v;
std::cout << "v.a => " << v.a[0] << ", " << v.a[1] << "\n";
return 0;
}
Where I've a constant array, it's always been done as static. If you can accept that, this code should compile and run.
#include <stdio.h>
#include <stdlib.h>
class a {
static const int b[2];
public:
a(void) {
for(int i = 0; i < 2; i++) {
printf("b[%d] = [%d]\n", i, b[i]);
}
}
};
const int a::b[2] = { 4, 2 };
int main(int argc, char **argv)
{
a foo;
return 0;
}
You can't do that from the initialization list,
Have a look at this:
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
:)
A solution without using the heap with std::vector is to use boost::array, though you can't initialize array members directly in the constructor.
#include <boost/array.hpp>
const boost::array<int, 2> aa={ { 2, 3} };
class A {
const boost::array<int, 2> b;
A():b(aa){};
};
How about emulating a const array via an accessor function? It's non-static (as you requested), and it doesn't require stl or any other library:
class a {
int privateB[2];
public:
a(int b0,b1) { privateB[0]=b0; privateB[1]=b1; }
int b(const int idx) { return privateB[idx]; }
}
Because a::privateB is private, it is effectively constant outside a::, and you can access it similar to an array, e.g.
a aobj(2,3); // initialize "constant array" b[]
n = aobj.b(1); // read b[1] (write impossible from here)
If you are willing to use a pair of classes, you could additionally protect privateB from member functions. This could be done by inheriting a; but I think I prefer John Harrison's comp.lang.c++ post using a const class.
interestingly, in C# you have the keyword const that translates to C++'s static const, as opposed to readonly which can be only set at constructors and initializations, even by non-constants, ex:
readonly DateTime a = DateTime.Now;
I agree, if you have a const pre-defined array you might as well make it static.
At that point you can use this interesting syntax:
//in header file
class a{
static const int SIZE;
static const char array[][10];
};
//in cpp file:
const int a::SIZE = 5;
const char array[SIZE][10] = {"hello", "cruel","world","goodbye", "!"};
however, I did not find a way around the constant '10'. The reason is clear though, it needs it to know how to perform accessing to the array. A possible alternative is to use #define, but I dislike that method and I #undef at the end of the header, with a comment to edit there at CPP as well in case if a change.