Это же указатель и проблема с переменными типами

Я надеюсь, что это нормально — просто добавить кусок кода, который я не понимаю, почему он ведет себя так, как есть.

У меня две проблемы со следующим кодом.

1) Почему this указатель для двух экземпляров, показывающий одно и то же значение? Вот вывод программы:

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> > >]

Это показывает в 2 раза значение 0x7ffff1743950, Это удивляет меня, потому что я уверен, что первый экземпляр не уничтожен до создания второго.

2) Я стараюсь делать глубокие копии PS где orig_ptr установлены на оригинал. Здесь используется настройка рекурсивной настройки шаблона. Так orig_ptr на каждом уровне следует соблюдать иерархию и указывать соответственно. Я не понимаю, почему код компилируется с F{{(void(Is),j,ptr->F[Is])...}} (он отмечен в коде) и почему он не компилируется с F{{(void(Is),j,&ptr->F[Is])...}}? (что я бы предположил правильно). Я не вижу какой конструктор T (ака RS<WJ<float> >) компилятор вызывает. Здесь нет RS<WJ<float> >::RS(Jit&,RS<WJ<float> >) существует только версия указателя.

#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);
}

** РЕДАКТИРОВАТЬ **

Я добавил интерфейс указателя WJ так что процедура создания экземпляра F может пройти весь путь вниз. Я думал, что это может быть связано с SFINE. Но это не так.

Попробовал это с g ++ — 4.7 (Ubuntu / Linaro 4.7.2-4precise1) 4.7.2 с -O0,

** РЕДАКТИРОВАТЬ **

Ответ @ sehe указал мне правильное направление. Конечно, void(Is) не требуется во втором типе JV Конструкторы. Только в первом типе, там он используется для имитации std::fill, Но там мы в списке инициализатора! Реализация по умолчанию оператора последовательности помогает устранить (void)Is полностью.

Теперь во втором случае есть другое использование Isа именно в ptr->F[Is], поэтому нет необходимости вводить искусственное void, Теперь это выглядит лучше:

** РЕДАКТИРОВАТЬ **

JV(Jit& j,JV<T,N>* ptr, indices<Is...>) :
jit(j), orig_ptr(ptr), F{{T(j,&ptr->F[Is])...}} { }

Он компилируется и работает нормально сейчас!

Тем не менее, проблема 1 остается: почему this 2 раза то же самое?!?

2

Решение

Расширение пакета аргументов шаблона здесь:

F {{(void(Is),j,ptr->F[Is])...}}

очень креативно, но не то, что вы ожидаете.

(void(Is),j,ptr->F[Is])

это одно выражение, использующее оператор последовательности (operator,). Который имеет примерно ту же семантику, что и следующий блок «псевдо-функции»:

{
(void)Is;
(void)j;
return ptr->F[Is];
}

Обратите внимание, как Is а также j не имеют никакого другого эффекта, кроме побочных эффектов, которых у них нет. Таким образом, все выражение эквивалентно

F {{(ptr->F[Is])...}}

И, честно говоря, мне не удалось понять смысл вашего кода. Вот небольшое подтверждение концепции, которую я сделал, чтобы убедиться, что синтаксис, который вы используете после Можно Работа:

#include <iostream>
#include <vector>
#include <array>

typedef std::vector<std::string> Vec;

template <int... I>
void foo(Vec const& v)
{
std::array<std::string, sizeof...(I)> expand {{ v.at(I)... }};
for(auto i: expand)
std::cout << i << '\n';
}

int main()
{
const Vec v { "zero", "one", "two", "three", "four", "etc" };
foo<2,1,3,0>(v);
foo<42>(v);
}

Выходы:

two
one
three
zero
terminate called after throwing an instance of 'std::out_of_range'
what():  vector::_M_range_check

Таким образом, он делает именно то, что вы ожидаете (протестировано в GCC и Clang ++)

2

Другие решения

Так как есть два отпечатка с этим = 0x7ffff1743950 появляются перед «пойти на это», они от построения w. Следующее «пойти на это» происходит от создания copyw, и я подозреваю, что после этого вы получите дополнительный вывод с этим =.

В вашем СП типа вы член:

std::array<T,N> F

и поскольку PS и RS наследуют от JV тип, предоставленный в JV, то PS обработки, которым является RS, означает, что F в JV, из которого получена PS, имеет PS, в котором происходит от JV.

0

По вопросам рекламы [email protected]