идиоматический способ преобразования `class ` в `class` оператор преобразования

#c #type-conversion #operator-overloading #idioms

#c #тип-преобразование #оператор-перегрузка #идиомы

Вопрос:

Предположим, что существует шаблонный класс template <class T> myclass; .

Существует ли идиоматический способ разрешить преобразование объектов из неконстантных T в объекты из const T ?

В принципе, я хочу, чтобы следующее преобразование выполнялось неявно:

 void f(myclass<const int> x);

myclass<int> a;
f(a); // should compile
  

ВАЖНОЕ РЕДАКТИРОВАНИЕ:

Похоже, что ответ очень тривиален (и вопрос довольно глупый), но в нем есть что-то очень концептуальное (по крайней мере, для меня).

У меня создалось впечатление, что мне нужно условно включить оператор преобразования, потому что оператор преобразования из myclass<const T> в myclass<const T> не имеет никакого смысла, т. Е. Мне нужно объявить оператор преобразования тогда и только тогда T , когда он был const указан. Я ожидал, что компилятор пожалуется на избыточный оператор преобразования.

Теперь, учитывая, что компилятор доволен оператором преобразования идентификаторов, который преобразует тип X в X , в чем разница между оператором присваивания или конструктором копирования и оператором преобразования идентификаторов?

MSVC выдает предупреждение для оператора преобразования идентификаторов. Это не здорово.

Ответ №1:

Вы можете сделать это с помощью оператора преобразования, который возвращает a myclass с указанным типом const. Это выглядит так

 template<typename T>
struct myclass
{
    T foo;
    operator myclass<const T>() { return myclass<const T>{foo}; }
};
  

а затем в

 int main() 
{ 
    myclass<int> a{42};
    f(a); // should compile
}
  

компилятор неявно вызовет его для вас.


Если у вас уже есть myclass<const int> и вы передаете его f , вам не нужно беспокоиться о какой-либо двусмысленности, поскольку конструктор копирования является точным совпадением, так что это то, что вызывается. Однако, если вы хотите отключить оператор преобразования, когда T он уже const есть, вы можете использовать

 template<typename U = T, std::enable_if_t<!std::is_const_v<U>, bool> = true> 
operator myclass<const U>() { return myclass<const U>{foo}; }
  

Комментарии:

1. @Yashas В этом случае произойдет «постоянный коллапс», вы все равно получите const T . myclass<const int> это operator myclass<const T> будет come operator myclass<const const int> , который сворачивается в operator myclass<const int>

2. Я немного смущен. Оператор преобразования для преобразования из X в X не имеет особого смысла? Это должен быть оператор присваивания?

3. Я подумал, что мне нужно будет условно включить оператор преобразования.

4. @Yashas «что, если T уже имеет значение const?» Он будет скомпилирован, если foo правильно инициализирован .

5. @Yashas Если у вас уже есть myclass<const T> , то он не будет вызывать оператор преобразования, поскольку конструктор копирования является точным совпадением.