2016-05-02 3 views
2

Проблема: я столкнулся с многочисленными дублирующими функциями для поддержки различных типов почти идентичных массивов. Например, функция Foo может быть доступна в следующих версиях:Конструктор шаблонов

void foo (int v); // single value, 99% of all use cases. 
void foo (std::initializer_list<int> v); 
void foo (const std::vector<int> &v); 
void foo (int *v, int size); 

Это дублирование беспокоит меня. Я хотел бы иметь одну функцию foo, которую можно вызывать с любыми типами данных, подобными массиву (с одним значением, очевидно, рассматриваемым как массив размером 1).

Возможные решения включают в себя:

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

. Моя реализация называется mem_range, которая представляет собой векторный интерфейс (включающий только операции, которые не изменяют размер вектора, очевидно). Предполагается, что различные типы массивов обрабатываются через различные конструкторы mem_range.

У меня проблема с конструктором, который должен принять std :: array. Проблема заключается в размере массива, который является частью определения шаблона - я не могу понять, как создать конструктор, который будет принимать массивы любого размера.

template<typename T> 
class mem_range { 
    public: 
     mem_range (T *begin, T *end) { } // ok 
     mem_range (std::vector<T> &vec) { } // ok 

     template<int array_size> 
     mem_range<array_size> (std::array<T, array_size> &arr) { } // not ok 
} 

Последний конструктор дает "ошибка C2988: неузнаваемый шаблон декларация/определение" на MSVC2015. Сейчас я пережил немало вариаций, но ничего не делает компилятор счастливым.

Просто чтобы быть ясно, на основе ответов, которые я читал на подобные вопросы здесь, на StackOverflow:

  • Изменение размеров массивов, как данные в любом случае не в области. Если бы я хотел эту возможность, я бы просто передал std :: vector.
  • Я знаю, что есть много вопросов с похожими названиями. Ни у кого из них, кажется, нет достойных ответов, обычно не получающих ничего, кроме «зачем вы этого хотите?».

Я пытаюсь сделать эту работу над MSVC2015 и современным GCC, поэтому C++ 14/17 в порядке (насколько поддерживается).

+0

Когда вы пишете код, напишите его как можно проще и понятнее - не беспокойтесь об оптимизации до тех пор, пока у вас не будет фактического набора данных для профиля. Беспокойство о стоимости создания массива из 1 элемента, вероятно, не будет чем-то, что сделает или сломает вашу программу - удержание ошибок, построив их просто, тем не менее, может спасти вас от некоторых серьезных головных болей позже. – xaxxon

+0

Это система 300 000 строк, используемая для высокопроизводительного научного анализа, и производительность заметно снизилась, когда я попытался объединить все эти функции в одну (векторную) версию. Я работаю над этим почти 20 лет, надеюсь, что это будет «позже» в вашей книге ... –

+0

«Это накладывает некоторые накладные расходы на распределение памяти при каждом использовании, и поскольку 99% моих применений предназначены для одиночных значений Я нахожу это нежелательным ». на самом деле не передает эту информацию. – xaxxon

ответ

3

При объявлении шаблонного конструктора шаблон понимается как функция-конструктор, поэтому вам не нужно указывать его там.

После аргумента массива вам также не хватает закрывающей скобки >.

Так что конструктор должен выглядеть следующим образом:

template<int array_size> 
mem_range(std::array<T, array_size>) { } 

И конечно, следует рассмотреть возможность передачи объекта массива в качестве ссылки на константу, и с помощью правильного типа (смотри, например,this std::array reference`), т.е.

template<std::size_t array_size> 
mem_range(std::array<T, array_size> const&) { } 
+2

'std :: array' использует' std :: size_t', а не 'int' btw. – Jarod42

+0

Хотя я уверен, что в какой-то момент я попытался использовать этот вариант, я должен был сделать что-то не так в то время - это работает. Благодаря! Кроме того, что касается вопроса size_t - спасибо, я учту это. –

0

Вы можете сделать ARRAY_SIZE необязательное значение класса шаблона.

template<typename T, int array_size=0> 
class mem_range { 
public: 
    mem_range (T *begin, T *end) { } // ok 
    mem_range (std::vector<T> &vec) { } // ok 
    mem_range (std::array<T, array_size> &array) { } 
}