Почему передача такого типа параметра переменного размера по значению невозможна? - PullRequest
1 голос
/ 19 ноября 2010

У нас есть структура, подобная приведенной ниже:

template<size_t size>
class Container{
 public:
  char characters[size];
};

И у нас есть функция, подобная приведенной ниже:

template <size_t size>
void function(Container<size> input,size_t Size){
 //all instances do exactly same thing and with regard to Size that determines the size of object
}

Теперь в C ++ для каждого значения размера используется отдельный экземпляр функции.будет создан, и, очевидно, это неправильно в этом случае, поскольку все экземпляры делают одно и то же, чтобы избежать этого, первым параметром функции должен быть указатель (char * pointer) вместо объекта, чтобы принимать любой массив с любым размером, устраняя необходимостьдля функции, которая будет шаблонизирована, но мне любопытно иметь единственную функцию, которая принимает параметр переменного размера, как описано выше, который не разрешен в C ++, что-то вообще невозможное для реализации и генерации сборки, или как-то приводит к неэффективной реализации в терминахскорости / памяти?

Ответы [ 6 ]

4 голосов
/ 19 ноября 2010

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

class ContainerBase {
 private: // can't be copied
  ContainerBase(ContainerBase const& o);
  ContainerBase &operator=(ContainerBase &);

 protected:
  ContainerBase(char *datap):datap(datap) { }

 public:
  char *data() { return datap; }

 private:
  char *datap;
};

template<std::size_t size>
class Container : public ContainerBase {
 public:
  Container():ContainerBase(d.characters)
  Container(Container const& o):ContainerBase(d.characters), d(o.d) 
  { }

  Container &operator=(Container const& o) {
    d = o.d;
    return *this;
  }

  struct {
   char characters[size];
  } d;
};


void function(ContainerBase const& input, std::size_t Size){
 /* operate on input.data() */
}

В таком маленьком классе он, вероятно, не окупится,но соотношение стоимость / использование увеличивается по мере роста независимых операций или самого класса.Обратите внимание, что если ваша цель состоит в том, чтобы класс был агрегатным, то описанный выше способ неосуществим.Вам нужно будет либо делегировать работу какой-то другой не шаблонной функции и жить с (возможно, очень маленькими) сгенерированными специализациями шаблонов, либо вы просто передаете адрес массива вручную.Это также помогло бы сделать не шаблонные функции более общими

template<std::size_t size>
class Container : public ContainerBase {
 public:
  char *data() { return characters; }

 public:
  char characters[size];
};

// note that this function works in plain arrays too
void function(char *input, std::size_t Size){
 /* operate on input */
}

function(c.data(), N);

Кстати, тогда вы находитесь на boost::array<char, N>, который предоставляет именно этот интерфейс и другие полезные функции (все еще являющиеся совокупными), хотя это и слишком общее в том смысле, что оно не зафиксировано на char.

1 голос
/ 19 ноября 2010

Одно из возможных решений заключается в том, чтобы функция с заданным размером передавала реальную работу обычной функции, которая принимает размер в качестве обычного параметра:

#include <cstddef>
#include <cstdio>

template <size_t size>
struct Container
{
    char characters[size];
};

template <size_t size>
inline void function(const Container<size>& input)
{
    real_work(input.characters, size);
}

void real_work(const char* p, size_t len)
{
    while (len--) puts(p++);
}

int main()
{
    Container<6> x = {"hello"};
    function(x);
}

Обратите внимание, что я сознательно назвал разные типы аргументов по-разному, чтобы вы не запутались.

1 голос
/ 19 ноября 2010

Обычно, когда вам нужен параметр IN, передайте встроенные типы по значению и другие типы по ссылке на const, т.е.

template< size_t size >
void function( Container<size> const& input,size_t Size )
{
 //all instances do exactly same thing and with regard to Size that determines the size of object
}

При таком определении есть вероятность, что компилятор + компоновщик оптимизирует все так, что будет только одна версия машинного кода function.

Я был немного удивлен, когда впервые проверил простую небольшую примерную программу, которая, выражая ее с помощью полиморфизма времени компиляции (шаблонов), производила меньший и более эффективный код, чем выражение с полиморфизмом времени выполнения!

Попробуйте сами, и если вы удивитесь так же, как я когда-то был, тогда Хорошо! В противном случае, есть вероятность, что не будет существенной разницы. Но в некоторых случаях вы можете найти то, что в прежние времена называлось «раздуванием кода шаблона», а затем пришло время игнорировать его или измерить, достаточно ли это важно для выполнения работы по переводу во время полиморфизма во время выполнения.

Теперь на ваш вопрос,

"Мне любопытно иметь одну функцию который принимает переменный размер параметр, как указано выше, это не разрешено C ++ это что-то невозможное вообще реализовать и сгенерировать сборка, или как-то приводит к неэффективная реализация с точки зрения скорость / память? "

Нет, невозможно преобразовать полиморфизм во время компиляции в эффективный полиморфизм во время выполнения или просто без полиморфизма . Тем более, что вы уже передаете размер во время выполнения (который, вероятно, гарантированно меньше фиксированного размера).

Безопасный способ - использовать std::string из стандартной библиотеки C ++, заголовок <string>. Это включает в себя динамическое распределение где-то во внутренних органах std::string, которое выполняется автоматически для вас, но влияет на эффективность. Но ваш код, содержащий char[size] characters, не был допустимым C ++, и это указывает на уровень начинающего, поэтому есть вероятность, что ваш дизайн не был выбран по какой-либо веской причине - следовательно, выполните:

class Container
{
public:
    std::string characters;
};

void function( Container const& input )
{
    // whatever, using e.g. input.characters.length()
}

Приветствия и hth.,

0 голосов
/ 19 ноября 2010

Это плохой дизайн в любом случае. В любом случае, передача массивов по значению, структурам или классам крайне неэффективна как во времени, так и в пространстве, поскольку весь массив должен быть скопирован в целевой кадр стека. Передайте ссылку.

0 голосов
/ 19 ноября 2010

Будет ли что-то подобное приемлемым для вас:

class BaseContainer{ /* ... */ };

template<size_t size>
class Container : public BaseContainer{
 public:
  char[size] characters;
};

void function(BaseContainer input,size_t Size){
  //
}
0 голосов
/ 19 ноября 2010

Контейнер <1> отличается от типа , чем Контейнер <2>, и передача указателя ничего не решит, поскольку они будут указателями на разные типы .

Не думаете ли вы, что size должен быть параметром конструктора контейнера, а не шаблонным значением?

...