Я думаю, что проблема довольно распространенная, поэтому должно быть известное решение.Я придумал один, но я не очень доволен, поэтому я спрашиваю здесь, надеясь, что кто-то может помочь.
Скажем, у меня есть функция, подпись которой
template<typename T>
void foo(const MyArray<const T>& x);
Значение const в параметре шаблона не позволяет мне изменять содержимое массива, поскольку (по причинам, не входящим в этот вопрос), методы доступа ([]
и ()
) для MyArray<T>
всегда помечаются как const и возвращают ссылки на T
(следовательно, const обеспечивает безопасность, поскольку MyArray<T>::operator[]
возвращает T&
, а MyArray<const T>::operator[]
возвращает const T&
).
Отлично.Однако шаблоны с различными аргументами шаблона не связаны, поэтому я не могу связать ссылку на MyClass<T>
со ссылкой MyClass<const T>
, то есть я не могу сделать это
MyArray<double> ar(/*blah*/);
foo(ar);
Обратите внимание, что,без ссылки приведенный выше код будет работать при условии , что существует конструктор копирования, который позволяет мне создавать MyArray<const T>
из MyArray<T>
.Однако я не хочу удалять ссылку, так как построение массива будет происходить много раз , и, несмотря на относительно низкую стоимость, его стоимость будет складываться.
Так что вопрос: как я могу вызвать foo
с MyArray<T>
?
Мое единственное решение на данный момент таково:
MyArray<T> ar(/*blah*/);
foo(reinterpret_cast<MyArray<const T>>(ar));
(на самом деле в моем коде я скрыл переинтерпретацию ввстроенная функция с более подробным названием, но конец игры тот же).Класс MyArray
не имеет специализации для const T
, что делает его не подлежащим повторному толкованию, поэтому приведение должно быть «безопасным».Но это не очень хорошее решение для чтения.Альтернативой может быть дублирование подписи foo
, чтобы иметь версию, принимающую MyArray<T>
, реализация которой выполняет приведение и вызывает версию const.Проблема в этом заключается в дублировании кода (и у меня довольно много функций foo
, которые нужно дублировать).
Возможно, какая-то дополнительная магия шаблона на подписи foo
?Цель состоит в том, чтобы передать оба значения MyArray<T>
и MyArray<const T>
, сохраняя при этом постоянную корректность (то есть заставить компилятор лаять, если я случайно изменил ввод в теле функции).
Редактировать 1: класс MyArray
(реализация которого не находится под моим контролем) имеет методы доступа const, поскольку он хранит указатели.Таким образом, вызов v[3]
изменит значения в массиве, но не члены , хранящиеся в классе (а именно, указатель и некоторые метаданные, подобные интеллектуальному указателю).Другими словами, объект де-факто не модифицирован средствами доступа, хотя массив есть.Это семантическое различие.Не уверен, почему они пошли в этом направлении (у меня есть идея, но слишком долго объяснять).
Редактировать 2 : Я принял один из двух ответов (хотя они были несколько похожи).Я не уверен (по причинам, которые долго объяснять), что класс-оболочка выполним в моем случае (возможно, я должен подумать об этом).Я также озадачен тем фактом, что, хотя
template<typename T>
void foo(const MyArray<const T>& x);
MyArray<int> a;
foo(a);
не компилируется, следующее делает
void foo(const MyArray<const int>& x);
MyArray<int> a;
foo(a);
Примечание: MyArray
предлагает шаблонный «конструктор копирования» с подписью
template<typename S>
MyArray(const MyArray<S>&);
, поэтому он может создать MyArray<const T>
из MyArray<T>
.Я озадачен, почему это работает, когда T
явно, в то время как это не работает, если T
является параметром шаблона.