Elegant way to initialize non-static array member

M

mathieu

Hi,

Consider the following (*). Is there a way to rewrite it so that it
remains convenient (N is being recomputed when array v is modified)
*and* compiles :)

Thanks,
-Mathieu

(*)
template <typename T, unsigned int N>
struct Functor
{
T values[N];
};

int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);
Functor<double,N> f = v; // will not compile
//Functor<double,7> f = { {0, 1, 4, 9, 16, 25, 36 } }; // need to
compute 7 by hand...

return 0;
}
 
M

mathieu

Hi,

Consider the following (*). Is there a way to rewrite it so that it
remains convenient (N is being recomputed when array v is modified)
*and* compiles :)

Thanks,
-Mathieu

(*)
template <typename T, unsigned int N>
struct Functor
{
T values[N];

};

int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);
Functor<double,N> f = v; // will not compile
//Functor<double,7> f = { {0, 1, 4, 9, 16, 25, 36 } }; // need to
compute 7 by hand...

return 0;

}

Super-ugly solution:

#define V {0, 1, 4, 9, 16, 25, 36 }
int main()
{
const double v[] = V;
const unsigned int N = sizeof(v) / sizeof(v[0]);
Functor<double,N> f = { V };
....
}
 
V

Victor Bazarov

mathieu said:
Hi,

Consider the following (*). Is there a way to rewrite it so that it
remains convenient (N is being recomputed when array v is modified)
*and* compiles :)

Thanks,
-Mathieu

(*)
template <typename T, unsigned int N>
struct Functor
{
T values[N];
};

Add this function:

template<class T, unsigned N> Functor<T,N> makeFunctor(T (&a)[N])
{
Functor<T,N> f;
std::copy(a, a+N, f.values);
return f;
}
int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);
Functor<double,N> f = v; // will not compile
//Functor<double,7> f = { {0, 1, 4, 9, 16, 25, 36 } }; // need to
compute 7 by hand...

Functor said:
return 0;
}

Final code:

template <typename T, unsigned int N>
struct Functor
{
T values[N];
};

#include <algorithm>
template <typename T, unsigned int N>
Functor<T,N> makeFunctor(T const (&a)[N])
{
Functor<T,N> f;
std::copy(a, a + N, f.values);
return f;
}

int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);

Functor<double,N> f = makeFunctor(v);

return 0;
}

V
 
M

mathieu

mathieu said:
Consider the following (*). Is there a way to rewrite it so that it
remains convenient (N is being recomputed when array v is modified)
*and* compiles :)
....

Final code:

template <typename T, unsigned int N>
struct Functor
{
T values[N];
};

#include <algorithm>
template <typename T, unsigned int N>
Functor<T,N> makeFunctor(T const (&a)[N])
{
Functor<T,N> f;
std::copy(a, a + N, f.values);
return f;
}

int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);

Functor<double,N> f = makeFunctor(v);

return 0;
}

nice and simple !

Thanks,
-Mathieu
 
T

terminator

...





Final code:
template <typename T, unsigned int N>
struct Functor
{
T values[N];
};
#include <algorithm>
template <typename T, unsigned int N>
Functor<T,N> makeFunctor(T const (&a)[N])
{
Functor<T,N> f;
std::copy(a, a + N, f.values);
return f;
}
int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);
Functor<double,N> f = makeFunctor(v);
return 0;
}

nice and simple !

Thanks,
-Mathieu- Hide quoted text -

- Show quoted text -

sorry to terminate, but this 'assigning to default constructed' not
initializing.
OP`s ugly solution is more efficient if 'T' has none-trivial
constructors.

regards,
FM.
 
P

peter koch

mathieu wrote:
Hi,
Consider the following (*). Is there a way to rewrite it so that it
remains convenient (N is being recomputed when array v is modified)
*and* compiles :)
Final code:
template <typename T, unsigned int N>
struct Functor
{
T values[N];
};
#include <algorithm>
template <typename T, unsigned int N>
Functor<T,N> makeFunctor(T const (&a)[N])
{
Functor<T,N> f;
std::copy(a, a + N, f.values);
return f;
}
int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);
Functor<double,N> f = makeFunctor(v);
return 0;
}
nice and simple !
Thanks,
-Mathieu- Hide quoted text -
- Show quoted text -

sorry to terminate, but this 'assigning to default constructed' not
initializing.
No. It is copyconstructing.
OP`s ugly solution is more efficient if 'T' has none-trivial
constructors.

No. Not if any modern (less than say 10 years old) C++ compiler is
used.
 
M

mathieu

mathieu wrote:
Hi,
Consider the following (*). Is there a way to rewrite it so that it
remains convenient (N is being recomputed when array v is modified)
*and* compiles :)
...
Final code:
template <typename T, unsigned int N>
struct Functor
{
T values[N];
};
#include <algorithm>
template <typename T, unsigned int N>
Functor<T,N> makeFunctor(T const (&a)[N])
{
Functor<T,N> f;
std::copy(a, a + N, f.values);
return f;
}
int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);
Functor<double,N> f = makeFunctor(v);
return 0;
}
nice and simple !
Thanks,
-Mathieu- Hide quoted text -
- Show quoted text -
sorry to terminate, but this 'assigning to default constructed' not
initializing.

No. It is copyconstructing.
OP`s ugly solution is more efficient if 'T' has none-trivial
constructors.

No. Not if any modern (less than say 10 years old) C++ compiler is
used.

Those kind of questions always kills me. I never learn assembly, and I
would have no way to know that std::copy is indeed doing the right
thing in this case. Any clue on how to see that ?

Thanks
-Mathieu
 
V

Victor Bazarov

mathieu said:
Those kind of questions always kills me. I never learn assembly, and I
would have no way to know that std::copy is indeed doing the right
thing in this case. Any clue on how to see that ?

Not sure what you mean by "the right thing", but std::copy will most
likely do 'memcpy' on arrays of POD, which is usually quite efficient;
as to non-trivial constructors, I believe 'terminator' is referring to
the inefficiency due to assigning that 'std::copy' has to do. Although
there is no way to tell whether it's inefficient until it is measured
in a real-world situation.

The problem with the macro solution is the symbol 'V' you have to live
with in the program. It is global, it has no type, and if you have to
have several of those, you quickly pollute the translation unit with
those identifiers. It's more difficult to read as well (since the 'V'
macro lives separately from the places where it is used).

Theoretical inefficiency versus code maintainability... It's a common
issue with which software designers have to deal every day.

V
 
A

Alex Vinokur

Final code:

template <typename T, unsigned int N>
struct Functor
{
T values[N];
};

#include <algorithm>
template <typename T, unsigned int N>
Functor<T,N> makeFunctor(T const (&a)[N])
{
Functor<T,N> f;
std::copy(a, a + N, f.values);
return f;
}

int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);
-----------------------------------------------
Here Microsoft Visual C++ 2005 produces an error
Functor<double,N> f = makeFunctor(v); -----------------------------------------------

return 0;
}
[snip]


Microsoft Visual C++ 2005 produces the following error
=========================
C2440: 'initializing' : cannot convert from 'Functor<T,N>' to
'Functor<T,N>'
with
[
T=const double,
N=7
]
and
[
T=double,
N=7
]
No user-defined-conversion operator available that can perform
this conversion, or the operator cannot be called
=============================================

Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn
 
V

Victor Bazarov

Alex said:
Final code:

template <typename T, unsigned int N>
struct Functor
{
T values[N];
};

#include <algorithm>
template <typename T, unsigned int N>
Functor<T,N> makeFunctor(T const (&a)[N])
{
Functor<T,N> f;
std::copy(a, a + N, f.values);
return f;
}

int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);
-----------------------------------------------
Here Microsoft Visual C++ 2005 produces an error
Functor<double,N> f = makeFunctor(v); -----------------------------------------------

return 0;
}
[snip]


Microsoft Visual C++ 2005 produces the following error
=========================
C2440: 'initializing' : cannot convert from 'Functor<T,N>' to
'Functor<T,N>'
with
[
T=const double,
N=7
]
and
[
T=double,
N=7
]
No user-defined-conversion operator available that can perform
this conversion, or the operator cannot be called
=============================================

Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn

Good to know.

V
 
T

terminator

[snip]


Final code:
template <typename T, unsigned int N>
struct Functor
{
T values[N];
};
#include <algorithm>
template <typename T, unsigned int N>
Functor<T,N> makeFunctor(T const (&a)[N])
{
Functor<T,N> f;
std::copy(a, a + N, f.values);
return f;
}
int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);

-----------------------------------------------
Here Microsoft Visual C++ 2005 produces an error> Functor<double,N> f = makeFunctor(v);

-----------------------------------------------
return 0;
}

[snip]

Microsoft Visual C++ 2005 produces the following error
=========================
C2440: 'initializing' : cannot convert from 'Functor<T,N>' to
'Functor<T,N>'
with
[
T=const double,
N=7
]
and
[
T=double,
N=7
]
No user-defined-conversion operator available that can perform
this conversion, or the operator cannot be called
=============================================

Why are not we going to treat intrinsic arrays as distinct coy
constructible types?
They can simply be fancied as some intrinsic template.

regards,
FM.
 
A

Alex Vinokur

On Nov 7, 4:47 pm, "Victor Bazarov"
[snip]
Good to know.
[snip]


Compiler aCC has a probblem with this program too.

============= foo.cpp =============

#include <algorithm>
using namespace std;

template <typename T, unsigned int N>
struct Functor
{
T values[N];
};

template<typename T, unsigned int N>
Functor<T,N> makeFunctor(T (&a)[N])
{
Functor<T,N> f;
copy(a, a + N, f.values);
return f;
}

int main()
{
const double v[] = {0, 1, 4, 9, 16, 25, 36 };
const unsigned int N = sizeof(v) / sizeof(v[0]);

Functor<double,N> f = makeFunctor(v);

return 0;
}


===================================



aCC: HP C/aC++ B3910B A.06.13 [Nov 27 2006]
============= Compilation =============
"foo.cpp", line 5: warning #2368-D: class "Functor<const double, 7U>"
defines no constructor to initialize the following:
const member "Functor<T, N>::values [with T=const double,
N=7U]"
struct Functor
^
detected during instantiation of class "Functor<T, N> [with
T=const double, N=7U]" at line 23

"foo.cpp", line 23: error #2312: no suitable user-defined conversion
from "Functor<const double, 7U>" to "Functor<double, 7U>" exists
Functor<double,N> f = makeFunctor(v);
^

"foo.cpp", line 13: error #2369-D: variable "f" has an uninitialized
const or reference member
Functor<T,N> f;
^
detected during instantiation of "Functor<T, N>
makeFunctor(T (&)[N]) [with T=const double, N=7U]" at line 23

"/opt/aCC/include_std/algorithm", line 2023: error #2137: expression
must be a modifiable lvalue
*__result = *__first;
^
detected during:
instantiation of "_OutputIter std::copy(_InputIter,
_InputIter, _OutputIter) [with _InputIter=const double *,
_OutputIter=const double *]" at line 14 of "foo.cpp"
instantiation of "Functor<T, N> makeFunctor(T (&)[N])
[with T=const double, N=7U]" at line 23 of "foo.cpp"

3 errors detected in the compilation of "foo.cpp".
=======================================


Alex Vinokur
email: alex DOT vinokur AT gmail DOT com
http://mathforum.org/library/view/10978.html
http://sourceforge.net/users/alexvn
 
T

terminator

[...]
Why are not we going to treat intrinsic arrays as distinct coy
constructible types?

Because that would break C compatibility.

including castability to appropariate pointers will remove any
incompatibilities .The internal interface of intrinsic array can be :

template <typename T, unsigned size_t n>
struct ___intrinsic_array{

___intrinsic_array(const ___intrinsic_array&);

typedef const T* ___CP;
typedef T* ___NP;
typedef volatile T* ___VP;

typedef const T& ___CR;
typedef T& ___NR;
typedef volatile T& ___VR;

inline operator ___CP()const
{return reinterpret_cast<___CP>(this);};
inline operator ___NP ()
{return reinterpret_cast<___NP >(this);};
inline operator ___VP()volatile
{return reinterpret_cast<___VP>(this);};

inline ___CR operator[](const size_t& i)const
{return *(operator ___CP()+i);};
inline ___NR operator[](const size_t& i)
{return *(operator ___NP()+i);};
inline ___VR operator[](const size_t& i)volatile
{return *(operator ___VP()+i);};

//assignment and construction can be defined as well.

};

regards,
FM.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top