#c #class #templates
#c #класс #шаблоны
Вопрос:
С помощью следующего кода, если я попытаюсь преобразовать массив шаблонов в std::string вместо компилятора, использующего ожидаемый метод преобразования std::string , возникает проблема разрешения неоднозначности (поскольку он пытается вызвать методы преобразования массива):
#include <iostream>
template<typename TemplateItem>
class TestA
{
public:
TemplateItem Array[10];
operator const TemplateItem *() const {return Array;}
operator const std::string() const;
};
template<>
TestA<char>::operator const std::string() const
{
std::string Temp("");
return Temp;
}
int main()
{
TestA<char> Test2;
std::string Temp("Empty");
Temp = Test2; //Ambiguity error. std::string or TemplateItem * ?
return 0;
}
Какие изменения мне нужно внести в код, чтобы сделать его таким, чтобы код корректно и неявно разрешался в функции преобразования std::string ? Особенно учитывая, что const TemplateItem * будет обрабатываться как массив с нулевым завершением (чего, скорее всего, не будет).
Комментарии:
1. поскольку
operator std::string
возвращается по значению, это не обязательноconst std::string
. Устраняет ли это проблему?2. @MooingDuck: изменение его с const на non-const не имеет заметного эффекта. Возможно, стоит отметить, что std::string имеет три разные функции преобразования, одна из которых принимает массив символов, а другая — std::string .
Ответ №1:
Во-первых, причина, по которой у вас есть двусмысленность: вы предоставляете как преобразование char*
, так и преобразование std::string const
, и std::string
им нравится оба.
Кстати, прежде чем перейти к вашему вопросу, const
in operator std::string const
когда-то был хорошей идеей, которую отстаивал, например, Скотт Мейерс, но в настоящее время она не очень хороша: она препятствует эффективному перемещению.
В любом случае, повторите вопрос, просто избегайте неявных преобразований. Сделайте эти преобразования явными. Теперь я ответил на это в ответ на другой вопрос SO, и кто-то (я полагаю, что этот человек троллил) прокомментировал, что C 98 не поддерживает explicit
операторы преобразования типов. Технически это было достаточно верно, но довольно глупо как технический комментарий. Потому что вам не нужно использовать explicit
ключевое слово (поддерживаемое C 11), и действительно, это не очень хороший способ сделать преобразования явными. Вместо этого просто назовите эти преобразования: используйте именованные функции-члены, а не операторы преобразования.
#include <iostream>
template<typename TemplateItem>
class TestA
{
public:
TemplateItem Array[10];
TemplateItem const* data() const { return Array; }
std::string str() const;
};
template<>
std::string TestA<char>::str() const
{
return "";
}
int main()
{
TestA<char> test2;
std::string temp( "Empty" );
temp = test2.str(); // OK.
temp = test2.data(); // Also OK.
}
Приветствия и привет.
Комментарии:
1. У вас есть источник, который объясняет неэффективность const ? Было бы интересно почитать.
2. Демонстрация именованного оператора преобразования не пойдет amis.
3. @Pubby8:
const
предотвращает операции перемещения. Раньше люди использовали «оптимизацию обмена», чтобы добиться такой эффективности. Операции перемещения заставляют компилятор выполнять это автоматически.4. @Mooing Duck: не существует такого понятия, как «именованный оператор преобразования». Однако именованных преобразований в стандартной библиотеке предостаточно. Например
std::string::c_str()
, или .std::ostringstream::str()
5. Я бы логически подумал, что std::string использовал бы операционный приоритет для одного из своих собственных типов по сравнению с вызовом шаблонной функции.
Ответ №2:
Я добавлю, подумав об этом, вот рассуждения и что нужно сделать:
Оператор const TemplateItem *(); Должен быть удален.
Почему? Никогда не будет случая, когда вы хотели бы неявного преобразования TestA (или любого шаблонного класса) в массив TemplateItem с неизвестным размером — потому что это не имеет абсолютно никакой проверки границ (массив может иметь размер 1 или 10 или 1000 или 0) и, вероятно, приведет к сбою, если вызывающая функция иликласс получил массив, понятия не имея, какого он размера.
Если массив необходим, либо используйте operator[] для прямых элементов, либо getArray (что будет сигнализировать о намерении пользователя передать массив неизвестной длины).
Сохранить оператор const std::string . Код будет скомпилирован. Предотвращены возможные проблемы с памятью в будущем.
(Alf за его усилия был выбран в качестве «правильного» ответа, хотя это более логичный вариант)