I hope it's okay to just throw in a piece of code which I don't understand why it is behaving like it is.
I have two problems with the following code.
1) Why is the this
pointer for the two instances showing the same value? Here the output of the program:
WJ::WJ(Jit&)
this = 0x7ffff1743950 JV<T, N>::JV(Jit&, indices<Is ...>) [with int ...Is = {0}; T = WJ<float>; int N = 1]
RS<T>::RS(Jit&) [with T = WJ<float>]
this = 0x7ffff1743950 JV<T, N>::JV(Jit&, indices<Is ...>) [with int ...Is = {0}; T = RS<WJ<float> >; int N = 1]
PS<T>::PS(Jit&) [with T = RS<WJ<float> >]
go for it
ptr = 0x7ffff1743950 JV<T, N>::JV(Jit&, JV<T, N>*, indices<Is ...>) [with int ...Is = {0}; T = RS<WJ<float> >; int N = 1]
PS<T>::PS(const PS<T>&) [with T = RS<WJ<float> >; PS<T> = PS<RS<WJ<float> > >]
It shows 2 times the value 0x7ffff1743950
. This wonders me because I am sure the first instance is not destroyed before the second is created.
2) I try to make deep copies of an PS
where the orig_ptr
are set to the original. The here used setup is a recursive template instantiation setup. So orig_ptr
on each level should respect the hierarchy and point accordingly. What I don't understand is why does the code compile with F{{(void(Is),j,ptr->F[Is])...}}
(it's marked in the code) and why does it not compile with F{{(void(Is),j,&ptr->F[Is])...}}
? (which I would assume correct). I don't see which constructor of T
(aka RS<WJ<float> >
) the compiler is calling. There is no RS<WJ<float> >::RS(Jit&,RS<WJ<float> >)
only the pointer version exists.
#include<iostream>
#include<array>
struct Jit {};
template <int... Is>
struct indices {};
template <int N, int... Is>
struct build_indices
: build_indices<N-1, N-1, Is...> {};
template <int... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<class T,int N>
struct JV {
JV(Jit& j) : JV(j,build_indices<N>{}) {}
template<int... Is>
JV(Jit& j, indices<Is...>) :
jit(j), F{{(void(Is),j)...}} {
std::cout << "this = " << (void*)this << " " << __PRETTY_FUNCTION__ << "\n";
}
JV(Jit& j,JV<T,N>* ptr) : JV(j,ptr,build_indices<N>{}) {}
template<int... Is>
JV(Jit& j,JV<T,N>* ptr, indices<Is...>) :
// Why does this not compile with &ptr->F[Is] ??
// What is it calling now (there is no T::T(Jit&,sub_T))
jit(j), orig_ptr(ptr), F{{(void(Is),j,ptr->F[Is])...}} {
std::cout << "ptr = " << (void*)ptr << " " << __PRETTY_FUNCTION__ << "\n";
}
std::array<T,N> F;
JV<T,N>* orig_ptr;
Jit& jit;
};
template<class T>
struct RS : public JV<T,1>
{
RS(Jit &j): JV<T,1>(j) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
RS(Jit &j, RS* orig): JV<T,1>(j,orig) {
std::cout << "orig = " << orig << " " << __PRETTY_FUNCTION__ << "\n";
}
};
template<class T>
struct PS : public JV<T,1>
{
PS(Jit& j): JV<T,1>(j) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
PS(const PS& rhs) : JV<T,1>(rhs.jit,const_cast<JV<T,1>*>( static_cast<const JV<T,1>*>(&rhs) ) ) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
template<class T>
struct WJ
{
WJ(Jit& j) {
std::cout << "WJ::WJ(Jit&)\n";
}
WJ(Jit& j,WJ* ptr) {
std::cout << __PRETTY_FUNCTION__ << "\n";
}
};
int main() {
Jit j;
PS<RS<WJ<float> > > w(j);
std::cout << "go for it\n";
PS<RS<WJ<float> > > wcopy(w);
}
** EDIT **
I added the pointer interface to WJ
so that the instantiation procedure of F
can recurse down the whole way. I thought it might be due to SFINE. But it wasn't.
Tried this with g++-4.7 (Ubuntu/Linaro 4.7.2-4precise1) 4.7.2 with -O0
.
** EDIT **
@sehe's answer pointed me in the right direction. Of course, the void(Is)
is not needed in the second type of JV
constructors. Only in the first type, there it is used to simulate a std::fill
. But there we are in the initializer list! The default implementation of the sequence operator helps to eliminate the (void)Is
completely.
Now in the 2nd case there is another use of Is
, namely in ptr->F[Is]
, so no need to introduce the artificial void
. Now, this looks better:
** EDIT **
JV(Jit& j,JV<T,N>* ptr, indices<Is...>) :
jit(j), orig_ptr(ptr), F{{T(j,&ptr->F[Is])...}} { }
It compile and runs fine now!
However, the 1 problem still remain: Why is this
2x the same ?!?