Is there a way to create a static const class value that is initialized with a loop? - c++11

A static member may be declared const, but then it must be initialized in the declaration. Consider the following case of a static array to be initialized with code in loops:
class A {
private:
enum { SIZE = 360 };
static double* vertices;
public:
static void staticInit();
};
double* A::vertices = new double[SIZE];
void A::staticInit() {
double a = 0, b = 0;
for (int i = 0; i < SIZE; i++, a += .01, b += .02)
vertices[i] = sin(a) + c2 * sin(b);
}
The code above would work. But if the intent is to make vertices constant, then declaring it const will give a compile error on the staticInit function.
In older C++ I would declare the pointer const, and cast it to non-const just in this function, but today, compilers won't allow this because it is unsafe. Of course, not declaring the pointer const is even less unsafe.
Is there any clean way out?

Create a makeVertices function that returns an std::array, then initialize the static value by invoking it:
constexpr std::size_t size = 360;
std::array<double, size> makeVertices()
{
std::array<double, size> vertices;
double a = 0, b = 0;
for (int i = 0; i < size; i++, a += .01, b += .02)
vertices[i] = sin(a) + c2 * sin(b);
return vertices;
}
(Both makeVertices and size could be defined inside A.)
class A {
private:
static std::array<double, size> vertices;
};
std::array<double, size> A::vertices = makeVertices();
Also note the use of constexpr instead of enum to represent compile-time numerical constants - that's idiomatic C++11.

I don't see why you couldn't make everything const that you care about. To simplify the usecase:
const T * const p = Init();
T * Init()
{
T * result = new T[n];
for (std::size_t i = 0; i != n; ++i)
InitOne(result[i]);
return result;
}
You should be able to apply this scheme to your static class member.

Related

MSVC warn that uninitialized local variable used, but I did initialize it in my code

Im tring to assign a float number with an expression when declare it.
But I got but I get wrong result and msvc2019 warns me about use of uninitialized variable.
template <int N, typename Viewer, typename Point = std::array<float, N>>
struct PixelToCoordinateWrapper;
template <typename Viewer, typename Point>
struct PixelToCoordinateWrapper<2, Viewer, Point> {
static constexpr auto Impl = [](float px, float py,
const Viewer &viewer) -> Point {
float ratio_x;
ratio_x = px / viewer.ViewPortWidth();
// This is OK
float ratio_y = py / viewer.ViewPortHeight();
std::cout << ratio_y; // wrong value.
// warning C4700: uninitialized local variable 'ratio_y' used
float r_wh = viewer.ViewPortScaleX() / viewer.ViewPortScaleY();
std::cout << r_wh; // wrong value
// warning C4700: uninitialized local variable 'r_wh' used
float offset_x, offset_y;
if (viewer.LengthX() / viewer.LengthY() > r_wh) {
offset_x = viewer.LengthX() * ratio_x;
offset_y = viewer.LengthX() * ratio_y;
offset_y = offset_y / r_wh;
} else {
offset_x = viewer.LengthY() * ratio_x;
offset_y = viewer.LengthY() * ratio_y;
offset_x = offset_x * r_wh;
}
return {viewer.CenterX() - viewer.LengthX() / 2 + offset_x,
viewer.CenterY() - viewer.LengthY() / 2 + offset_y};
};
};
And some relevant codes:
template <typename Viewer, typename ObjectContainer, typename Point>
struct SelectPolygonWrapper<2, Viewer, ObjectContainer, Point> {
static constexpr auto Impl = [](ObjectContainer *gl_object_container,
const Viewer &viewer, const float px,
const float py) -> int {
using RawViewerType = std::remove_cv_t<std::remove_reference_t<Viewer>>;
Point p = PixelToCoordinateWrapper<2, RawViewerType, Point>::Impl(px, py,
viewer);
return PointInPolygonWrapper<2, Point, ObjectContainer>::Impl(
gl_object_container, p);
};
template <int N, typename Point, typename ObjectContainer>
struct PointInPolygonWrapper;
template <typename Point, typename ObjectContainer>
struct PointInPolygonWrapper<2, Point, ObjectContainer> {
/// Return the index of the gl_object in container.
/// If no gl_object is selected, return -1.
static constexpr auto Impl = [](ObjectContainer *gl_object_container,
const Point &point) -> int { return -1; };
};
The following is the main program code where the error occurs:
int count = SelectPolygonWrapper<
2, Viewer, ObjectContainer>::Impl(draw_object_, viewer_,
event->position().x(),
event->position().y());
/// Wrong
However, when I call PixelToCoordinateWrapper::Impl directly, the result is correct, and the compiler gives me no warning.
auto p = PixelToCoordinateWrapper<2, ViewerInfo>::Impl(
event->position().x(), event->position().y(), viewer_);
} /// Right
I don't understand what's going on here, is there something wrong with the instantiation of the class template? Or is it an implementation issue with the MSVC compiler?

How to pass Comparator to user define Templeted class?

I want to create a generalized heap data structure, and facing an issue with passing template comparator.
template<typename T, typename C = less<T> > class Heap{
vector<T> *heap;
public:
Heap(vector<T> *arr){
heap = new vector<T> (arr->begin(), arr->end());
build_heap();
}
void build_heap(){
size_t n = heap->size();
for (size_t i=(n-1)/2; i>=0; i--){
shiftDown(i);
}
}
void shiftDown(size_t i){ /// heap logic
while(i < heap->size()){
size_t child = 2*i+1;
// int min_ind = 2*i+1;
if(child >= heap->size())
return;
if(child+1 < heap->size()){
if( C(heap->at(child+1),heap->at(child)) ){ // <----- using C as comparator
child++;
}
}
if( C(heap->at(child), heap->at(i)) ){ // <----- using C as comparator
swap(heap->at(child), heap->at(i));
i = child;
}
else
break;
}
}
};
int main(){
vector<int> v={8,7,6,5,4,3,2,1};
Heap<int, less<int> > heap(&v);
}
error
heap.cpp: In instantiation of ‘void Heap<T, C>::shiftDown(size_t) [with T = int; C = std::less<int>; size_t = long unsigned int]’:
heap.cpp:15:4: required from ‘void Heap<T, C>::build_heap() [with T = int; C = std::less<int>]’
heap.cpp:10:3: required from ‘Heap<T, C>::Heap(std::vector<_Tp>*) [with T = int; C = std::less<int>]’
heap.cpp:49:34: required from here
heap.cpp:32:9: error: no matching function for call to ‘std::less<int>::less(__gnu_cxx::__alloc_traits<std::allocator<int>, int>::value_type&, __gnu_cxx::__alloc_traits<std::allocator<int>, int>::value_type&)’
32 | if( C(heap->at(child+1),heap->at(child)) ){
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
detailed error
i'm following same syntex of declaration as stl c++ do, still i'm getting error. please help me out.
template<typename T, typename C = less<T> > class Heap;
any help or pointer to help is appreciated. thank you.
template<class T>
class Comparator{
bool operator()(const T &a, const T &b){
...
// returns logic
}
}
template<class T, class Comp >
class AnyClass{
public:
...
void function(){
// code ...
Comp<T>()(obj1, obj2);
}
...
}
calling sytex :
...
AnyClass *obj = new AnyClass<Type , Comparator>();
obj.function()
...
passing Comparator to templated class and when we need to compare objects
we create a functional object and call operator() with args to compare.
In question, that object is less<int>.
Comp<T>()(obj1, obj2);

minmax that returns modifiable references

With all the new features of C++ (C++11 suffices I think), what prevents from having a std::minmax function that returns a pair of references.
In this way, if one feeds two modifable references, they can be modified. Is this opening a can of worms?
#include<functional>
// maybe all this options can be simplified
template<class T1, class T2> struct common;
template<class T> struct common<T, T>{using type = T;};
template<class T> struct common<T const&, T&>{using type = T const&;};
template<class T> struct common<T&, T const&>{using type = T const&;};
template<class T> struct common<T, T&>{using type = T const&;};
template<class T> struct common<T&, T>{using type = T const&;};
template<class T> struct common<T const&, T>{using type = T const&;};
template<class T> struct common<T, T const&>{using type = T const&;};
template<class T1, class T2, class Compare = std::less<>, class Ret = typename common<T1, T2>::type>
std::pair<Ret, Ret> minmax(T1&& a, T2&& b, Compare comp = {}){
return comp(b, a) ?
std::pair<Ret, Ret>(std::forward<T2>(b), std::forward<T1>(a))
: std::pair<Ret, Ret>(std::forward<T1>(a), std::forward<T2>(b));
}
Test:
#include<cassert>
int main(){
{
int a = 1;
int b = 10;
auto& small = minmax(a, b).first;
assert(small == 1);
small += 1;
assert(a == 2);
}{
int const a = 1;
int b = 10;
auto& small = minmax(a, b).first;
assert(small == 1);
// small += 1; error small is const reference, because a was const
}{
int a = 1;
int const b = 10;
auto& small = minmax(a, b).first;
assert(small == 1);
// small += 1; error small is const reference, because a was const
}{
int const a = 1;
int const b = 10;
auto& small = minmax(a, b).first;
assert(small == 1);
// small += 1; error small is const reference, because a was const
}{
int b = 10;
auto& small = minmax(int(1), b).first;
assert(small == 1);
// small += 1; error small is const reference, because first argument was const
}{
int a = 1;
auto& small = minmax(a, int(10)).first;
assert(small == 1);
// small += 1; error small is const reference, because second argument was const
}
{
int const a = 1;
auto& small = minmax(a, int(10)).first;
assert(small == 1);
// small += 1; error small is const reference, because both arguments are const
}
{
// auto& small = minmax(int(1), int(10)).first; // error, not clear why
auto const& small = minmax(int(1), int(10)).first; // ok
// auto small2 = minmax(int(1), int(10)).first; // also ok
assert(small == 1);
// small += 1; error small is const reference, because both arguments are const
}
}
There was a paper kind of along these lines a long time ago, by Howard Hinnant: N2199. Its very opening example demonstrates the precise problem you're trying to solve:
The function can not be used on the left hand side of an assignment:
int x = 1;
int y = 2;
std::min(x, y) = 3; // x == 3 desired, currently compile time error
It goes on to list as examples the frequently dangling reference problem, mixing types, and being useful with move-only types, and goes on to propose new versions of min and max that address all of these problems - it includes a very thorough implementation at the bottom (which is too long to paste here). Implementing minmax() based on that should be pretty straightforward:
template <class T, class U,
class R = typename min_max_return<T&&, U&&>::type>
inline
std::pair<R, R>
minmax(T&& a, U&& b)
{
if (b < a)
return {std::forward<U>(b), std::forward<T>(a)};
return {std::forward<T>(a), std::forward<U>(b)};
}
The paper was rejected at the time. It's possible it could come back though.
Being able to get back mutable references is nice, but being able to avoid dangling references is even nicer. Anonymously quoting from an example I saw recently:
template<typename T> T sign(T);
template <typename T>
inline auto frob(T x, T y) -> decltype(std::max(sign(x - y), T(0))) {
return std::max(sign(x - y), T(0));
}
This function has undefined behaviour for all inputs (the narrowest
contract possible?).
Note that your common implementation has this problem. These cases:
template<class T> struct common<T, T&>{using type = T const&;};
template<class T> struct common<T&, T>{using type = T const&;};
template<class T> struct common<T const&, T>{using type = T const&;};
template<class T> struct common<T, T const&>{using type = T const&;};
all dangle. What this means if I have:
int i = 4;
auto result = your_minmax(i, 5);
result here is a pair<int const&, int const&>, one of which is a reference to i and the other of which dangles. All of these cases have to do using type = T; in order to be safe.

Vector proxy const and non const operation

I wrote a matrix template which is based on a std::vector. I am facing a problem when I want to proceed to an mathematical operation between two matrices: one which is a const reference and the other one which is not const and not a reference.
I am passing through a proxy to retrieve data stored in the std::vector:
template<typename T>
class Mat
{
public:
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
typedef typename std::vector<T>::size_type size_type;
private:
class Proxy
{
public:
Proxy(Mat& o, value_type i) : o(o), i(i)
{}
operator value_type()
{ return o.m[i]; }
reference operator=(const_reference other)
{ return o.m[i] = other; }
reference operator+=(const_reference other)
{ return o.m[i] += other; }
value_type operator*(const_reference other)
{ return o.m[i] * other; }
private:
Mat& o;
size_type i;
};
// Matrix methods and operator overloads.
Proxy operator[](size_type i)
{ return Proxy(*this, i); }
const Proxy operator[](size_type i) const
{ return Proxy(*this, i); }
Here is a sample from an extract of a test class which triggered an error:
void Test::buildMemoryMatrix(const Mat<int>& state)
{
Mat<int> t = state.getTransposed();
for(Mat<int>::size_type i = 0; i < state.rows(); ++i)
{
for(Mat<int>::size_type j = 0; j < t.cols(); ++j)
{
for(Mat<int>::size_type k = 0; k < state.cols(); ++k)
{
if(i == j)
{ continue; }
memory[i * memory.cols() + j] += state[i * state.cols() + k] * t[k * t.cols() + j];
}
}
}
}
Some precisions about the Mat<int> methods and Test class members:
The memory is a member of Test. It is represented as a Mat<int> object;
Mat::getTransposed() returns a transposed of a matrix;
Mat::rows() returns the number of rows of a matrix;
Mat::cols() returns the number of columns of a matrix
The following line give me some trouble:
memory[i * memory.cols() + j] += state[i * state.cols() + k] * t[k * t.cols() + j];
passing ‘const Mat::Proxy’ as ‘this’ argument discards qualifiers
[-fpermissive]
How to solve this problem?
Thanks for your answers.

Const-correct way to tell a function how to access required data from an arbitrary data structure?

In this game of life program the user tells the solve function how to access required data. Is it possible to be const-correct inside the function without supplying it with both const and non-const versions of data accessors? Clang complains about the constness of neighbor cell data when checking whether neighbors are alive or not (candidate function not viable: 1st argument ('const Cell') would lose const qualifier):
#include "array"
#include "iostream"
using namespace std;
struct Cell {
bool is_alive = false; int nr_live_neighs = 0;
};
template<
class Grid,
class Is_Alive_Getter,
class Nr_Live_Neighs_Getter
> void solve(
Grid& grid,
Is_Alive_Getter Is_Alive,
Nr_Live_Neighs_Getter Nr_Live_Neighs
) {
for (size_t i = 1; i < grid.size() - 1; i++) {
auto& cell = grid[i];
const auto // how to stay const-correct here?
&neigh_neg = grid[i - 1],
&neigh_pos = grid[i + 1];
if (Is_Alive(neigh_neg)) Nr_Live_Neighs(cell)++;
if (Is_Alive(neigh_pos)) Nr_Live_Neighs(cell)++;
}
for (auto& cell: grid) {
if (Nr_Live_Neighs(cell) == 3)
Is_Alive(cell) = true;
else if (Nr_Live_Neighs(cell) != 2)
Is_Alive(cell) = false;
Nr_Live_Neighs(cell) = 0;
}
}
int main() {
std::array<Cell, 10> grid;
for (size_t i = 0; i < grid.size(); i++) {
grid[i].is_alive = (i % 4 > 0);
}
solve(
grid,
[](Cell& cell_data) -> bool& {
return cell_data.is_alive;
},
[](Cell& cell_data) -> int& {
return cell_data.nr_live_neighs;
}
);
return 0;
}
I can use
if (Is_Alive(const_cast<decltype(cell)>(neigh_neg)))
instead of
if (Is_Alive(neigh_neg))
inside the solver but that feels hacky even though it doesn't seem to affect time to solution. What if a non-const reference isn't available to use in decltype? Is there a generic way to cast away the const by only referring to the const variable?

Resources