Saturday, June 27, 2020

Digest for comp.lang.c++@googlegroups.com - 25 updates in 3 topics

jacobnavia <jacob@jacob.remcomp.fr>: Jun 27 08:46AM +0200

Hi
 
I have implemented operator overloading in the context of the C
language, and I have a quetstion concerning the behavior of C++ with the
operator [ ] (indexing) and multi-dimensional arrays.
 
Supposing I have a 3 dimensional array of some type T.
 
T table[2][5][2]; // 2 planes, 5 rows, 2 columns
 
How do you overload the access to T?
 
Thanks in advance.
 
jacob
Bonita Montero <Bonita.Montero@gmail.com>: Jun 27 08:52AM +0200

Am 27.06.2020 um 08:46 schrieb jacobnavia:
> Supposing I have a 3 dimensional array of some type T.
> T table[2][5][2];  // 2 planes, 5 rows, 2 columns
> How do you overload the access to T?
 
Impossible !
You have to have an object at each level where you apply the
[]-operator. If you't declare a multidimensional vector, you'd
write this:
 
#include <vector>
 
using namespace std;
 
int main()
{
vector<vector<vector<int>>> threeDimensional;
// creates the the first element of the first, second and
// third dimension (compile with C++17 !)
threeDimensional.emplace_back().emplace_back().emplace_back();
threeDimensional[0][0][0] = 0;
}
Bonita Montero <Bonita.Montero@gmail.com>: Jun 27 09:11AM +0200

Maybe this is a more proper example:
 
#include <vector>
#include <iostream>
 
using namespace std;
 
int main()
{
vector<vector<vector<size_t>>> vvvi;
vvvi.reserve( 10 );
for( size_t i = 0; i != 10; ++i )
{
vector<vector<size_t>> &vvi = vvvi.emplace_back();
vvi.reserve( 10 );
for( size_t j = 0; j != 10; ++j )
{
vector<size_t> &vi = vvi.emplace_back();
vi.resize( 10 );
for( size_t k = 0; k != 10; ++k )
vi[k] = i << 16 | j << 8 | k;
}
}
size_t sum = 0;
for( size_t i = 0; i != vvvi.size(); ++i )
for( size_t j = 0; j != vvvi[i].size(); ++j )
for( size_t k = 0; k != vvvi[i][j].size(); ++k )
sum += vvvi[i][j][k];
cout << "sum: " << sum << endl;
}
jacobnavia <jacob@jacob.remcomp.fr>: Jun 27 10:22AM +0200

Le 27/06/2020 à 09:11, Bonita Montero a écrit :
>                 sum += vvvi[i][j][k];
>     cout << "sum: " << sum << endl;
> }
 
Sorry but I got
acob@rock64:~/lcc/book/test$ g++ tidx.cpp
tidx.cpp: In function 'int main()':
tidx.cpp:12:56: error: invalid initialization of non-const reference of
type 'std::vector<std::vector<long unsigned int> >&' from an rvalue of
type 'void'
vector<vector<size_t>> &vvi = vvvi.emplace_back();
~~~~~~~~~~~~~~~~~^~
tidx.cpp:16:50: error: invalid initialization of non-const reference of
type 'std::vector<long unsigned int>&' from an rvalue of type 'void'
vector<size_t> &vi = vvi.emplace_back();
~~~~~~~~~~~~~~~~^~
jacob@rock64:~/lcc/book/test$
 
Must be a problem somwhere but my C++ is too weak to figure it out.
 
Anyway thanks for your input.
Ian Collins <ian-news@hotmail.com>: Jun 27 08:49PM +1200

On 27/06/2020 18:46, jacobnavia wrote:
 
> Supposing I have a 3 dimensional array of some type T.
 
> T table[2][5][2]; // 2 planes, 5 rows, 2 columns
 
> How do you overload the access to T?
 
Some thing like:
 
#include <array>
 
using Column = std::array<int,2>;
using Row = std::array<Column,5>;
using Plane = std::array<Row,2>;
 
int main()
{
Plane plane;
plane[1][2][1] = 0;
 
Column col {1,2};
plane[1][1] = col;
}
 
?
 
--
Ian.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 27 10:51AM +0200

> jacob@rock64:~/lcc/book/test$
> Must be a problem somwhere but my C++ is too weak to figure it out.
> Anyway thanks for your input.
 
C++ supports emplace_back with a reference-return since C++17.
jacobnavia <jacob@jacob.remcomp.fr>: Jun 27 11:11AM +0200

Le 27/06/2020 à 10:51, Bonita Montero a écrit :
>> Must be a problem somwhere but my C++ is too weak to figure it out.
>> Anyway thanks for your input.
 
> C++ supports emplace_back with a reference-return since C++17.
 
I used:
g++ -std=c++17 tidx.cpp
 
The same error...
Melzzzzz <Melzzzzz@zzzzz.com>: Jun 27 09:32AM


> Supposing I have a 3 dimensional array of some type T.
 
> T table[2][5][2]; // 2 planes, 5 rows, 2 columns
 
> How do you overload the access to T?
 
You don't. Operator [] is single function. You call another [] on result
of previous [], and again.
 
 
--
current job title: senior software engineer
skills: c++,c,rust,go,nim,haskell...
 
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Svi smo svedoci - oko 3 godine intenzivne propagande je dovoljno da jedan narod poludi -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala
Bonita Montero <Bonita.Montero@gmail.com>: Jun 27 11:42AM +0200

>> C++ supports emplace_back with a reference-return since C++17.
 
> I used:
> g++ -std=c++17 tidx.cpp
 
Maybe an outdated standard-libary. Look here:
https://en.cppreference.com/w/cpp/container/vector/emplace_back
Since C++17 the STL shoud return a reference.
alelvb <alelvb@inwind.it>: Jun 27 01:29PM +0200

Il 27/06/20 08:46, jacobnavia ha scritto:
 
> How do you overload the access to T?
 
> Thanks in advance.
 
> jacob
 
I'm playing with 2 dimensional std::vectors, but you can extend
this for arrays with a bigger number of dimensions.
 
my code is maybe not the most orthodox but it works:
 
//******** cut here *********
 
#include <initializer_list>
#include <iostream>
#include <vector>
 
using uInt = long long unsigned int;
 
template <typename T>
class Matrix
{
public:
/* ===================
* the constructors
* =================== */
 
Matrix(std::initializer_list<std::initializer_list<T>> lil);
Matrix(const Matrix<T>& m) = default;
Matrix(Matrix<T>&& r) = default;
Matrix(uInt r, uInt c);
 
/* ===================
* member functions
* =================== */
 
uInt rows() const { return row; }
uInt columns() const { return col; }
 
std::vector<T> operator[] (const uInt r) const { return data.at(r); }
std::vector<T>& operator[] (const uInt r) { return data.at(r); }
 
~Matrix<T>() = default;
 
/* ===================
* the '<<' operator
* =================== */
 
friend std::ostream& operator<< (std::ostream& out, const Matrix<T>& m)
{
for(uInt i=0; i != m.rows(); ++i)
{
for(uInt j=0; j != m.columns(); ++j)
{
out << m.data[i][j] << ' ';
}
out << '\n';
}
return out;
}
 
/* ===================
* data members
* =================== */
 
private:
std::vector<std::vector<T>> data;
uInt row;
uInt col;
};
 
 
/* ===================
* constructor implem
* =================== */
 
template <typename T>
Matrix<T>::Matrix(std::initializer_list<std::initializer_list<T>> lil)
{
uInt r=0, count=0, maxcols=0;
 
for(auto y : lil)
{
++r;
std::vector<T> v;
data.push_back(v);
 
for(auto x : y)
{
++count;
}
 
if(count > maxcols)
maxcols = count;
 
count=0;
}
 
row = r;
col = maxcols;
 
// initialization
int i=0;
for(auto y : lil)
{
for(auto x : y)
{
data.at(i).push_back(x);
}
++i;
}
}
 
/* ===================
* the main function
* =================== */
 
int main()
{
Matrix<double> m {{0,1,2},{0,1,1},{1,0,1}};
 
std::cout << m << '\n';
}
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 27 04:51PM +0200

On 27.06.2020 08:46, jacobnavia wrote:
> Hi
 
> I have implemented operator overloading in the context of the C
> language,
 
I don't quite see what that could be about.
 
Some macro-based support for function overloading was added in C11, but
is that what you have leveraged?
 
Or what?
 
 
 
> Supposing I have a 3 dimensional array of some type T.
 
> T table[2][5][2];  // 2 planes, 5 rows, 2 columns
 
> How do you overload the access to T?
 
Generally you don't, because operator[] only takes a single argument.
 
That single argument can of course be a struct with two or more indices,
and/or the indexing result can be something that can further indexed.
The struct thing is just impractical notation. The indexable result
thing can be as simple as returning a pointer, but in this case it
exposes the array internals. Alternatively the result can be a proxy
object but that's both complex and bug prone and possibly inefficient.
 
So, for general indexing of a multidimensional array it's common to use
either the function call operator `operator()`, and/or named indexing
functions with names such as `at` or `item`.
 
Example:
 
 
-----------------------------------------------------------------------
#include <stddef.h> // ptrdiff_t
 
#include <array> // std::array
#include <utility> // std::enable_if, std::move
#include <vector> // std::vector
 
namespace my {
using
std::array,
std::enable_if_t, std::move,
std::vector;
 
using Size = ptrdiff_t;
using Index = ptrdiff_t;
 
template< int arity_param, class Value_param >
class Multidimensional_array_
{
public:
static constexpr int arity = arity_param;
using Value = Value_param;
 
static_assert( arity > 0 );
 
private:
vector<Value> m_items;
array<Size, arity> m_sizes;
 
template< class... Indices >
auto index_for( const Indices... index_args )
-> Index
{
const array<Index, arity> indices = {index_args...};
 
Size weight = 1;
Index result = 0;
for( int i = 0; i < arity; ++i ) {
result += indices[i]*weight;
weight *= m_sizes[i];
}
return result;
}
 
public:
// The first size is "innermost", opposite of a raw
multidimensional array.
template<
class... Size_types,
class = enable_if_t< sizeof...( Size_types ) == arity >
 
Multidimensional_array_( const Size_types... sizes ):
m_items( (1 * ... * sizes) ),
m_sizes{ sizes... }
{}
 
template<
class... Index_types,
class = enable_if_t< sizeof...( Index_types ) == arity >
 
auto operator()( const Index_types... indices ) const
-> const Value&
{ return m_items[index_for( indices... )]; }
 
template<
class... Index_types,
class = enable_if_t< sizeof...( Index_types ) == arity >
 
auto operator()( const Index_types... indices )
-> Value&
{ return m_items[index_for( indices... )]; }
 
Multidimensional_array_( const Multidimensional_array_& other )
= default;
Multidimensional_array_( Multidimensional_array_&& other ) =
default;
 
auto size( const int dimension ) const
-> Size
{ return m_sizes[dimension]; }
};
 
template< class Value_param >
using Array_2d = Multidimensional_array_<2, Value_param>;
 
template< class Value_param >
using Array_3d = Multidimensional_array_<3, Value_param>;
} // namespace my
 
#include <iomanip>
#include <iostream>
using
std::setw,
std::cout, std::endl;
 
auto main()
-> int
{
auto box = my::Array_3d<double>( 2, 5, 2 );
 
for( int z = 0; z < box.size( 2 ); ++z ) {
for( int y = 0; y < box.size( 1 ); ++y ) {
for( int x = 0; x < box.size( 0 ); ++x ) {
box( x, y, z ) = 100*(z + 1) + 10*(y + 1) + (x + 1);
}
}
}
 
for( int z = 0; z < box.size( 2 ); ++z ) {
for( int y = 0; y < box.size( 1 ); ++y ) {
for( int x = 0; x < box.size( 0 ); ++x ) {
cout << setw( 4 ) << box( x, y, z );
}
cout << endl;
}
cout << endl;
}
}
-----------------------------------------------------------------------
 
 
- Alf
jacobnavia <jacob@jacob.remcomp.fr>: Jun 27 05:13PM +0200

Le 27/06/2020 à 11:42, Bonita Montero a écrit :
 
> Maybe an outdated standard-libary. Look here:
> https://en.cppreference.com/w/cpp/container/vector/emplace_back
> Since C++17 the STL shoud return a reference.
 
YES!
I compiled in my macintosh and it worked. Before I was compiling in an
arm. Apparently the library of the arm system is a bit old
 
Thanks
Juha Nieminen <nospam@thanks.invalid>: Jun 27 03:33PM

> I have implemented operator overloading in the context of the C
> language
 
What does that even mean?
Juha Nieminen <nospam@thanks.invalid>: Jun 27 03:36PM

> You don't. Operator [] is single function. You call another [] on result
> of previous [], and again.
 
I wonder if it would break anything if support for multidimensional
operator[] would be added. It could work simply like this:
 
class MyClass
{
public:
void operator[](std::size_t i1, std::size_t i2)
{
std::cout << "[" << i1 << "][" << i2 << "]\n";
}
};
 
 
void foo()
{
MyClass obj;
obj[10][20];
}
 
Why add this kind of support? Because it would significantly
simplify overloading multidimensional indexing.
David Brown <david.brown@hesbynett.no>: Jun 27 06:28PM +0200

On 27/06/2020 17:36, Juha Nieminen wrote:
> }
 
> Why add this kind of support? Because it would significantly
> simplify overloading multidimensional indexing.
 
There is, I believe, I move towards sane multi-dimensional indexing
support in C++, in the form "obj[10, 20]" - the use of the comma
operator is deprecated within array expressions in C++20. But it will
take many generations of C++ standards before such array expressions can
be used - backwards compatibility is a bugger when you have to keep
supporting language design mistakes. Personally, I think /all/ use of
the comma operator should have been deprecated.
 
Another way of making multi-dimensional arrays with nice indexing is to
overload the function call operator, so that you can write:
 
obj(10, 20)
jacobnavia <jacob@jacob.remcomp.fr>: Jun 27 06:34PM +0200

Le 27/06/2020 à 16:51, Alf P. Steinbach a écrit :
 
> Some macro-based support for function overloading was added in C11, but
> is that what you have leveraged?
 
> Or what?
 
I repeat. I am the developer of the lcc-win compiler system, and in that
compiler I have implemented operator overloading, roughly similar to c++
with some differences.
 
>> T table[2][5][2];  // 2 planes, 5 rows, 2 columns
 
>> How do you overload the access to T?
 
> Generally you don't, because operator[] only takes a single argument.
 
In my system you have the operator [ ] (accessing an array for reading)
and the operator [ ] = (accessing an array for writing)
 
The last one takes 3 arguments: the object, the index, and the value.
 
Now, I wanted to know how C++ manages multi-dimensional array access,
and apparently it doesn't. So I have no c++ compatibility problem since
there isn't anything there.
 
Thanks for your input.
 
I compiled your code and it runs ok, but I would like to keep the []
notation.
 
jacob
jacobnavia <jacob@jacob.remcomp.fr>: Jun 27 06:40PM +0200

Le 27/06/2020 à 17:33, Juha Nieminen a écrit :
>> I have implemented operator overloading in the context of the C
>> language
 
> What does that even mean?
 
typedef struct { double real,double imag; } cmplx;
 
cmplx operator +(complx a,cmplx b) {
cmplx result;
 
result.real = a.real+b.real;
result.imag = a.imag+b.imag;
return result;
}
 
int main(void)
{
cmplx a,b={2,3},c={4,5};
c = a+b;
}
 
This compiles in the lcc-win compiler system. It is called "operator
overloading" and many languages support it like Fortran, c# and others.
It has been a standard feature of my compiler system since 2005.
Paavo Helde <eesnimi@osa.pri.ee>: Jun 27 09:05PM +0300

27.06.2020 19:28 David Brown kirjutas:
 
> be used - backwards compatibility is a bugger when you have to keep
> supporting language design mistakes. Personally, I think /all/ use of
> the comma operator should have been deprecated.
 
The comma operator is essential for for. There are uncountably many for
loop expressions using the comma operator and it can be never deprecated
there.
 
For [] I agree: ',' does not mean comma operator inside (), [] should
behave the same, just for symmetry. For lambda [] this already works so.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 27 08:32PM +0200

> This compiles in the lcc-win compiler system. It is called "operator
> overloading" and many languages support it like Fortran, c# and others.
> It has been a standard feature of my compiler system since 2005.
 
If you are not writing your own complex-class for educational purposes:
you can #include <complex> and thereby have a full blown complex-class
with all appropriate operators.
Cholo Lennon <chololennon@hotmail.com>: Jun 26 10:31PM -0300

On 6/26/20 6:40 AM, Alessandro Volturno wrote:
> features. It would be very useful, in my opinion, to offer the
> programmer a unique, standard way to handle the screen and to permit a
> uniform representation of these features graphically.
 
I don't know if your first assertion ("console programs are now widely
superseded by graphical UI") is true. Could you provide some
source/stats for that? IMHO the GUI apps are just the tip of the
iceberg... but a more or less 50-50 proportion is not crazy at all.
 
 
--
Cholo Lennon
Bs.As.
ARG
alelvb <alelvb@inwind.it>: Jun 27 10:13AM +0200

Il 27/06/20 03:31, Cholo Lennon ha scritto:
> superseded by graphical UI") is true. Could you provide some
> source/stats for that? IMHO the GUI apps are just the tip of the
> iceberg... but a more or less 50-50 proportion is not crazy at all.
 
No... I cannot give any statistics. I'm not competent on the
matter. I said that from my limited experience as amateur
self-taught programmer.
 
Sorry : )
Manfred <noname@add.invalid>: Jun 27 05:56PM +0200

On 6/27/2020 10:13 AM, alelvb wrote:
> matter. I said that from my limited experience as amateur
> self-taught programmer.
 
> Sorry : )
 
Even without accurate statistics one can easily get some idea: a typical
Linux (or *nix for that matter) server distribution does not include an
X server, which means there is no GUI at all.
It is an easy guess that there is quite a lot of server code running out
there.
Manfred <noname@add.invalid>: Jun 27 06:07PM +0200

>> benefit for the widespread of C++.
 
> Jave has a standard GUI built in to the JVM but it ended up being lowest common
> denominator and everyone hated it.
 
[...]
> control logic and low level access to the system. It is the job of libraries to
> use that low level access to provide I/O and other support services that will
> vary considerably from one machine to another.
 
Agreed, C++ is not meant o be an "all purpose" language - Stroustrup
himself says that no programmer should limit themselves to one language
only.
This is different from Java, for which one of the goals was to run the
entire system (and for example Android followed this path by deprecating
any non-Java application) - and still the result is hardly usable unless
the GUI subsystem is deeply rebuilt.
Juha Nieminen <nospam@thanks.invalid>: Jun 27 06:26AM


> That's what many think of as vector graphics. After all you pass it the
> endpoints of a vector, not the intervening pixels. And it can do
> antialiased lines of sorts.
 
Generally "vector graphics" refers to drawing pictures using
drawing elements like lines, curves, ellipses, splines and so on
and so forth, and most often this supports defining line thickness,
color, fill color, fill pattern, and oftentimes all kinds of
effects. Most usually high-quality antialiasing is supported to
avoid a pixelated look. It is what, for example, the SVG file format
is all about.
 
See https://en.wikipedia.org/wiki/Vector_graphics
 
Even at its simplest a "vector graphics" library ought to support
at least a few primitivies, like lines, circles, rectangles, etc.
Manfred <noname@add.invalid>: Jun 27 05:39PM +0200

On 6/27/2020 8:26 AM, Juha Nieminen wrote:
 
> See https://en.wikipedia.org/wiki/Vector_graphics
 
> Even at its simplest a "vector graphics" library ought to support
> at least a few primitivies, like lines, circles, rectangles, etc.
 
There is a fundamental difference between a data format like SVG or PS
and a rendering API like OpenGL that is deliberately kept close to the
hardware.
The former provides higher level primitives to ease the job of the
content provider. Runtime performance is of secondary concern.
The latter aims at maximum performance by providing as direct as
possible access to hardware functions.
 
It could certainly be possible to make GPU boards that render SVG
directly, but this kind of trajectory would clash with the differences
between the hardware development cycle and standards evolution.
 
I'll admit that I am not up to date with the latest standards, however
curves and splines are supported by the earlier versions of OpenGL
(still available on all implementations) as part of the utility library,
that substantially converts them into step-linear paths. Antialiasing is
also part of the OpenGL API as a /hint/, which means that
implementations are free to ignore it, but this is a problem of QoI
rather than of OpenGL itself.
 
What I find more meaningful is that one fundamental power of vector
graphics is that it can perform exact and efficient vector
*transformations* like scaling, rotations, gradients and textures - all
of this (and much more) has been part of OpenGL since day one.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: