Как jogojapan действительно дал ответ, я сделаю это сообщество wiki.
ИМО, это адекватное решение:
template < typename Iter8, typename Iter32 >
Iter32 Utf8toUtf32(Iter8 _from, Iter8 _from_end, Iter32 _dest, Iter32 _dest_end);
Это предназначено, чтобы вернуть то, что вы хотели _dest
, чтобы изменить.
Если вам действительно нужно вернуть int
, вы можете вернуть пару.
Чтобы отразить, какие итераторы должны быть прочитаны и которые должны быть записаны, вы можете использовать схему именования для параметров шаблона, например. InputIterator8
и OutputIterator32
.
Чтобы дать аналогию с функцией стандартной библиотеки:
std::vector<int> v = {1,2,3,4};
for(auto i = v.begin(); i != v.end();)
{
if(*i == 2)
{
i = v.erase(i); // iterator invalidated and new "next" iterator returned
}
}
Если вы хотите, чтобы ваша функция а) принимать массивы и б) быть аналогичны функциям стандартной библиотеки, я не» Нет другого пути, кроме как вернуть «измененные» итераторы.Единственная функция библиотеки, которую я знаю, которая фактически меняет пройденный итератор, равна std::advance
.
Пример:
template < typename Iter8, typename Iter32 >
std::tuple<int, Iter8, Iter32> Utf8toUtf32(Iter8 _from, Iter8 _from_end,
Iter32 _dest, Iter32 _dest_end);
char utf8String [] = "...some utf8 string ...";
wchar_t wideString [ 100 ];
char* pUtf8Res = nullptr;
wchar_t* pUtf16Res = nullptr;
int res = 0;
std::tie(res, pUtf8Res, pUtf16Res) = Utf8toUtf16(begin(pIter), end(pIter),
begin(wideString), end(wideString));
(Редактируйте jogojapan)
Если вы должны держать прохождения итераторы как ссылки, потому что вы хотите, чтобы обновить положение текста они указывают на обе проблемы, описанные в вопросе не может быть решена напрямую.
Проблема 1: Передача wideString
, который является локальным массивом, в функцию будет означать его тип распадается на wchar_t*
RValue, и что не может быть связанно с wchar_t *&
неконстантной ссылки. Другими словами, вы не можете изменить функцию адреса локального массива. Приведение его в указатель не изменяет этот факт, а компилятор ошибочен, когда принимает это решение.
Задача 2: Аналогичным образом, передача адреса nCodepoint
по ссылке невозможна, так как этот адрес не может быть изменен. Единственным решением является сохранение адреса в отдельный указатель, а затем передать, что:
unsigned long *pCodepoint = &nCodepoint;
Utf8toUtf32(pIter,PIter+5,pCodepoint,pCodepoint+1);
(Другой редактирование jogojapan)
Если вы хотите передать по ссылке, но вы хотите чтобы сделать функцию достаточно гибкой, чтобы принять не-ссылочные параметры, а также, вы можете предоставить перегруженные определения шаблона:
/* Using C++11 code for convenience. Rewriting in C++03 is easy. */
#include <type_traits>
template <typename T>
using noref = typename std::remove_reference<T>::type;
template <typename Iter8, typename Iter32>
int Utf8toUtf32 (Iter8 &from, const Iter8 from_end, Iter32 &dest, const Iter32 dest_end)
{
return 0;
}
template <typename Iter8, typename Iter32>
int Utf8toUtf32 (Iter8 &from, const Iter8 from_end, noref<Iter32> dest, const Iter32 dest_end)
{
noref<Iter32> p_dest = dest;
return Utf8toUtf32(from,from_end,p_dest,dest_end);
}
template <typename Iter8, typename Iter32>
int Utf8toUtf32 (noref<Iter8> from, const Iter8 from_end, Iter32 &dest, const Iter32 dest_end)
{
noref<Iter8> p_from = from;
return Utf8toUtf32(p_from,from_end,dest,dest_end);
}
template <typename Iter8, typename Iter32>
int Utf8toUtf32 (noref<Iter8> from, const Iter8 from_end, noref<Iter32> dest, const Iter32 dest_end)
{
noref<Iter8> p_from = from;
noref<Iter32> p_dest = dest;
return Utf8toUtf32(p_from,from_end,p_dest,dest_end);
}
вы можете назвать это со всеми видами с очетание яв ляю из lvalues и rvalues:
int main()
{
char input[] = "hello";
const char *p_input = input;
unsigned long dest;
unsigned long *p_dest = &dest;
std::string input_str("hello");
Utf8toUtf32(input,input+5,&dest,&dest+1);
Utf8toUtf32(p_input,p_input+5,&dest,&dest+1);
Utf8toUtf32(input,input+5,p_dest,p_dest+1);
Utf8toUtf32(p_input,p_input+5,p_dest,p_dest+1);
Utf8toUtf32(begin(input_str),end(input_str),p_dest,p_dest+1);
Utf8toUtf32(begin(input_str),end(input_str),&dest,&dest+1);
return 0;
}
Но имейте в виду: При пропускании RValue (например, массив или выражение, как &local_var
), то вызов будет работать и там не будет неопределенное поведение, но, конечно, адрес локальной переменной или массива, конечно, все равно не изменится. Таким образом, вызывающий не сможет в этой ситуации выяснить, сколько символов функция могла обработать.
В стороне: имена, такие как '_Iter8' и' _Iter32' (ведущее подчеркивание, за которым следует символ подчеркивания или заглавная буква) зарезервированы, поэтому ваш код имеет неопределенное поведение. –
C++ 11? Используйте ['std :: begin'] (http://en.cppreference.com/w/cpp/iterator/begin) и [' std :: end'] (http://en.cppreference.com/w/ cpp/iterator/end) (даже для массивов). Не C++ 11? Напишите свой собственный. – dyp
Вторая проблема связана с тем, что вы передаете свои итераторы в качестве ссылок. Есть ли причина, почему вы это делаете? Передача итераторов копией должна быть прекрасной. – jogojapan