相同的这个指针和可变类型的麻烦
Same this pointer and trouble with variadic types
我希望可以直接插入一段代码,但我不明白它为什么会这样。
我对以下代码有两个问题。
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> > >]
它显示值0x7ffff1743950
的2倍。这让我感到奇怪,因为我确信第一个实例在第二个实例创建之前不会被破坏。
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 itn";
PS<RS<WJ<float> > > wcopy(w);
}
**编辑**
我为WJ
添加了指针接口,以便F
的实例化过程可以一直递归。我想这可能是由于SFINE。但事实并非如此。
在g++-4.7(Ubuntu/Linaro 4.7.2-4precise1)4.7.2和-O0
中尝试过这一点。
**编辑**
@塞的回答为我指明了正确的方向。当然,在第二类JV
构造函数中不需要void(Is)
。只有在第一种类型中,它才用于模拟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
2x相同?!?
此处的模板参数包的扩展:
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++中测试)
由于有两个this=0x7ffff1743950的打印出现在"go for it"之前,它们来自于构造w。下面的一个"go for it"来自于构造copyw,我怀疑在那之后您会使用this=获得额外的输出。
在您的合资企业类型中,您是成员:
std::array<T,N> F
由于PS和RS都继承了JV提供的类型,处理PS是RS,这意味着PS来源的JV中的F具有来源于JV的PS。
- ArduinoJson 6.15.2:JsonObject没有命名类型
- 防止主数据类型C++的隐式转换
- 大量序列中核苷酸类型的快速计数
- 如何从C++中的依赖类型中获得它所依赖的类型
- 有关插入适配器的错误。[错误]请求从 'back_insert_iterator<vector<>>' 类型转换为非标量类型
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如何获取std::result_of函数的返回类型
- 从父命名空间重载类型
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 访问者访问变体并返回不同类型时出错
- 在VS2010-VS2015下编译时,如何使用decltype作为较大类型表达式的LHS
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- C++ 雷神库 - 使用资源加载器类时出现问题(不命名类型)
- 模板元程序查找相似的连续类型名称
- 使用基本和用户定义类型的名称查找麻烦
- 相同的这个指针和可变类型的麻烦
- 将向量传递到C 功能时的类型麻烦
- 在其他类中使用类类型的麻烦