2

我希望只输入一段我不明白它为什么会这样的代码是可以的。

下面的代码有两个问题。

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(aka )的哪个构造函数。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,即in 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 仍然存在:为什么this2x 相同?!?

4

2 回答 2

2

模板参数包的扩展在这里:

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

很有创意,但不是你所期望的。

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

是单个表达式,使用序列运算符( operator,)。它与以下“伪函数”块具有大致相同的语义:

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

注意除了副作用之外没有任何其他影响Isj它们没有。所以整个表达式等价于

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++ 中测试)

于 2012-11-14T20:59:33.670 回答
0

由于 this = 0x7ffff1743950 的两个打印出现在“go for it”之前,它们来自构造 w。“去吧”之后的一个来自构建 copyw ,我怀疑在此之后你还有额外的输出 this = 。

在您的合资企业类型中,您是成员:

std::array<T,N> F

并且由于 PS 和 RS 都从 JV 继承提供给 JV 的类型,处理 PS 是 RS,这意味着从 JV 派生 PS 的 F 具有从 JV 派生的 PS。

于 2012-11-14T17:36:29.300 回答