无法将 std::array 的一部分作为模板引用类型参数传递
Cannot Pass A Section Of An std::array As A Template Reference Type Argument
我想保持类似数据的数组连续进行处理。为简化起见,假设我想将 int
的数组与 char
的数组分开,这样当我想显示字符时,我可以连续遍历所有字符而无需获取整数。现在两个数组的前 32 个索引属于一个对象,接下来的 32 个索引属于另一个对象。我希望能够对数组应用一种“蓝图”或“千篇一律”,以将每个对象“拥有”的数组部分组合在一起。我的第一个想法是给每个对象一个成员变量,链接到它的数组部分,就像这样
struct NonTemp {
std::array<int, 32>& ints;
std::array<char, 32>& chars;
NonTemp(std::array<int, 32>& Ints, std::array<char, 32>& Chars) : ints(Ints), chars(Chars) {}
};
但我发现这样一个对象的大小在 32 位版本上是 8 个字节,在 64 位版本上是 16 个字节。它正在存储指针。地址在编译时是已知的,所以我想我应该能够用硬编码地址替换指针。模板非常适合让编译器解决这类问题,所以我尝试了这个:
template<std::array<int, 32>& ints, std::array<char, 32>& chars>
struct Temp {
std::array<int, 32>& GetInts() {
return ints;
}
std::array<char, 32>& GetChars() {
return chars;
}
};
std::array<int, 64> ints;
std::array<char, 62> chars;
void main() {
static std::array<int, 32>& proxyInts = *reinterpret_cast<std::array<int, 32>*>(&ints[32]);
static std::array<char, 32>& proxyChars = *reinterpret_cast<std::array<char, 32>*>(&chars[32]);
Temp<proxyInts, proxyChars> temp;
}
但是我收到一个编译器错误,指出需要一个编译时常量表达式。在做一些研究后,我发现关于 Whosebug 的另一个答案可能解释了原因:。它声称引用变量不是 id 表达式(类似于字符串文字)并且不能用作模板参数。那么有解决办法吗?或者有没有更好的方法来完成我想做的事情?为了便于测试,我提供了一些针对该情况的完整代码:
/*
* Stores pointers to references, increases object size by pointer size each
*/
struct NonTemp {
std::array<int, 32>& ints;
std::array<char, 32>& chars;
NonTemp(std::array<int, 32>& Ints, std::array<char, 32>& Chars) : ints(Ints), chars(Chars) {}
};
template<std::array<int, 32>& ints, std::array<char, 32>& chars>
struct Temp {
std::array<int, 32>& GetInts() {
return ints;
}
std::array<char, 32>& GetChars() {
return chars;
}
};
/*
* Replaces references to in with hard coded addresses, does not add to object size
*/
template<int& in>
struct Attempt {
int& GetInt() {
return in;
}
};
std::array<int, 64> ints;
std::array<char, 62> chars;
int in;
void main() {
NonTemp nonTemp = NonTemp(*reinterpret_cast<std::array<int, 32>*>(&ints), *reinterpret_cast<std::array<char, 32>*>(&chars));
std::cout << "Size of NonTemp: " << sizeof(nonTemp) << std::endl;
static std::array<int, 32>& proxyInts = *reinterpret_cast<std::array<int, 32>*>(&ints[32]);
static std::array<char, 32>& proxyChars = *reinterpret_cast<std::array<char, 32>*>(&chars[32]);
Temp<proxyInts, proxyChars> temp;
std::cout << "Size of Temp: " << sizeof(temp) << std::endl;
temp.GetInts()[0] = 2;
Attempt<in> attempt;
std::cout << "Size of Attempt: " << sizeof(attempt) << std::endl;
attempt.GetInt() = 10;
std::cout << "In: " << in << std::endl;
std::cout << "GetInt(): " << attempt.GetInt() << std::endl;
for (uint32_t i = 0; i < 64; ++i) {
std::cout << "Arr[" << i << "]: " << ints[i] << std::endl;
}
}
作为附加说明,每个对象“拥有”数组中相同数量的元素可能并不总是这样,我希望有一种方法可以让具有相似数据的不同对象拥有不同大小的部分的数组,但仍然知道有哪些成员,而不会浪费 RAM 存储指针,而我在编译时已经知道所有对象实例。
你不能 convert/cast (sub)std::array
到较小的。
std::span
(C++20 起) (C++20) 似乎合适:
template <std::array<int, 64>& ints,
std::array<char, 64>& chars,
std::size_t offset,
std::size_t size>
struct Temp
{
std::span<int, size> GetInts() { return std::span<int, size>{ &ints[offset], size}; }
std::span<char, size> Gethars() { return std::span<char, size>{ &chars[offset], size}; }
};
我想保持类似数据的数组连续进行处理。为简化起见,假设我想将 int
的数组与 char
的数组分开,这样当我想显示字符时,我可以连续遍历所有字符而无需获取整数。现在两个数组的前 32 个索引属于一个对象,接下来的 32 个索引属于另一个对象。我希望能够对数组应用一种“蓝图”或“千篇一律”,以将每个对象“拥有”的数组部分组合在一起。我的第一个想法是给每个对象一个成员变量,链接到它的数组部分,就像这样
struct NonTemp {
std::array<int, 32>& ints;
std::array<char, 32>& chars;
NonTemp(std::array<int, 32>& Ints, std::array<char, 32>& Chars) : ints(Ints), chars(Chars) {}
};
但我发现这样一个对象的大小在 32 位版本上是 8 个字节,在 64 位版本上是 16 个字节。它正在存储指针。地址在编译时是已知的,所以我想我应该能够用硬编码地址替换指针。模板非常适合让编译器解决这类问题,所以我尝试了这个:
template<std::array<int, 32>& ints, std::array<char, 32>& chars>
struct Temp {
std::array<int, 32>& GetInts() {
return ints;
}
std::array<char, 32>& GetChars() {
return chars;
}
};
std::array<int, 64> ints;
std::array<char, 62> chars;
void main() {
static std::array<int, 32>& proxyInts = *reinterpret_cast<std::array<int, 32>*>(&ints[32]);
static std::array<char, 32>& proxyChars = *reinterpret_cast<std::array<char, 32>*>(&chars[32]);
Temp<proxyInts, proxyChars> temp;
}
但是我收到一个编译器错误,指出需要一个编译时常量表达式。在做一些研究后,我发现关于 Whosebug 的另一个答案可能解释了原因:
/*
* Stores pointers to references, increases object size by pointer size each
*/
struct NonTemp {
std::array<int, 32>& ints;
std::array<char, 32>& chars;
NonTemp(std::array<int, 32>& Ints, std::array<char, 32>& Chars) : ints(Ints), chars(Chars) {}
};
template<std::array<int, 32>& ints, std::array<char, 32>& chars>
struct Temp {
std::array<int, 32>& GetInts() {
return ints;
}
std::array<char, 32>& GetChars() {
return chars;
}
};
/*
* Replaces references to in with hard coded addresses, does not add to object size
*/
template<int& in>
struct Attempt {
int& GetInt() {
return in;
}
};
std::array<int, 64> ints;
std::array<char, 62> chars;
int in;
void main() {
NonTemp nonTemp = NonTemp(*reinterpret_cast<std::array<int, 32>*>(&ints), *reinterpret_cast<std::array<char, 32>*>(&chars));
std::cout << "Size of NonTemp: " << sizeof(nonTemp) << std::endl;
static std::array<int, 32>& proxyInts = *reinterpret_cast<std::array<int, 32>*>(&ints[32]);
static std::array<char, 32>& proxyChars = *reinterpret_cast<std::array<char, 32>*>(&chars[32]);
Temp<proxyInts, proxyChars> temp;
std::cout << "Size of Temp: " << sizeof(temp) << std::endl;
temp.GetInts()[0] = 2;
Attempt<in> attempt;
std::cout << "Size of Attempt: " << sizeof(attempt) << std::endl;
attempt.GetInt() = 10;
std::cout << "In: " << in << std::endl;
std::cout << "GetInt(): " << attempt.GetInt() << std::endl;
for (uint32_t i = 0; i < 64; ++i) {
std::cout << "Arr[" << i << "]: " << ints[i] << std::endl;
}
}
作为附加说明,每个对象“拥有”数组中相同数量的元素可能并不总是这样,我希望有一种方法可以让具有相似数据的不同对象拥有不同大小的部分的数组,但仍然知道有哪些成员,而不会浪费 RAM 存储指针,而我在编译时已经知道所有对象实例。
你不能 convert/cast (sub)std::array
到较小的。
std::span
(C++20 起) (C++20) 似乎合适:
template <std::array<int, 64>& ints,
std::array<char, 64>& chars,
std::size_t offset,
std::size_t size>
struct Temp
{
std::span<int, size> GetInts() { return std::span<int, size>{ &ints[offset], size}; }
std::span<char, size> Gethars() { return std::span<char, size>{ &chars[offset], size}; }
};