C ++ массив нулевого размера, который не требует места в памяти?

При объявлении переменной-члена шаблонного класса, есть ли способ заставить ее требовать нулевой памяти в зависимости от значения какого-либо параметра шаблона?

Например, определить что-то вроде std::array<T,n> это потребовало бы нулевого места, когда n==0,

Например:

template<int num_optional_args> class C {
int some_variable;
std::array<int,num_optional_args> optional_args;
};

Есть ли способ исключить накладные расходы по num_optional_args==0?

Большинство реализаций std::array<T,n> зарезервировать место для одного T элемент, даже когда n==0,

Есть ли другое средство, которое бы зарезервировало нулевое пространство?
Почему это не является частью стандарта C ++?

3

Решение

Вы можете специализировать свой тип так, чтобы optional_args не существует, когда число равно нулю. Если вам нужно, чтобы объект существовал, то единственный способ, которым объект может существовать и на который можно ссылаться, фактически не занимая места, — это пустая оптимизация базового класса.

Вы можете использовать это следующим образом:

template<int num_optional_args>
class optional_args {
std::array<int,num_optional_args> args
public:
// whatever interface you want for the optional args.
void foo(int n) {
if (n < num_optional_args)
args[n];
throw std::runtime_error("out of range");
}
};

template<>
class optional_args<0> {
public:
// whatever interface you want for the optional args, specialized for 0 args.
void foo(int n) {
throw std::runtime_error("out of range");
}
};

template<int num_optional_args>
class C : optional_args<num_optional_args> {
int some_variable;
void bar() {
for (int i=0; i<num_optional_args; ++i) {
optional_args::foo(i);
}
}
};
4

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

Вам нужно либо зарезервировать место хотя бы для одного элемента, либо сохранить указатель на этот элемент.
Невозможно иметь структуру массива, которая принимает нуль объем памяти.

Следующая структура принимает только один int и один указатель при создании, что примерно равно нулю, как вы получите:

template<typename T>
class array {

int sz;
T *head;

};

Кроме того, концепция требования нулевого пространства в определении класса глупа. Желание, чтобы при создании экземпляра он занимал почти нулевое пространство, могло бы иметь смысл, и это можно сделать, параметризовав конструктор следующим образом:

template<typename T>
class array {

int sz;
T *head;

array(int n) {
if (n == 0) return;
head = new T[n];
}
};
1

как сказал преторианец, вы можете специализироваться на 0. И если вы хотите, чтобы все варианты класса C имели одинаковый интерфейс, вы могли бы иметь все C, производные от C<0>, вот так:
шаблон класса C;

template <> class C<0> {

int s;

public:
int blah();
};

template <int N> class C : public C<0>{

int a[N];
};

int C<0>::blah() {return s;}

int main() {

C<1> a;
C<0> b;
a.blah();
b.blah();
return 0;
}
1

Если вас не интересует POD-сущность вашей вещи, вы можете использовать Boost.CompressedPair:

template<int num_optional_args> class C {
boost::compressed_pair<int, std::array<int,num_optional_args>> data;
int& some_variable() { return data.first(); }
std::array<int,num_optional_args>& optional_args() { return data.second(); }
};

Если, скорее всего, std :: array является пустым классом, это должно снять накладные расходы. Но ваш класс больше не является POD, потому что не сжато_парой.

0

Я действительно не помню, является ли он полностью легальным в C ++, но я думаю, что он все еще в C: у вас может быть массив нулевого размера, но он должен быть последним членом определения структуры. Исторически он использовался для буферов переменной длины:

struct buffer
{
usigned int size;
byte data[0];
};

buf.data полностью пригодный массив array’n’pointer, так что если вы позаботитесь и malloc N + sizeof (int) байтов, то вы можете привести его к buffer, установить size к N и здесь вы идете, у вас есть N байт data массив с size префикс. И дело в том, что каждый такой буфер всегда будет иметь и начинаться с префикса «size», а затем иметь данные, так что вы можете привести каждый такой буфер к buffer и проверьте размер, а затем используйте * (данные + x) или данные [x] при условии, что 0

Смотри например http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html

Тем не менее, обратите внимание, что это C, а не C ++, но я почти уверен, что я видел такие хитрости в POD в C ++.

Кроме того, наиболее важным моментом является то, что такой массив будет иметь длину ноль. sizeof (buffer) == sizeof (int) в приведенном выше примере, но ТОЛЬКО если массив является последним членом. Если вы добавите еще одно поле после массива, то массив и это последнее поле должны иметь разные смещения, так что массив с нулевой длиной будет 1-байтовым (+ выровнять) только для того, чтобы иметь разные адрес. Не говоря уже о том, что ни один здравомыслящий компилятор не позволит вам объявить массив с нулевой длиной в середине структуры. Это действительно возможно только как хвост структуры.

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