正如jogojapan实际上给出了答案,我将把它变成一个社区维基。
IMO,这是一个足够的解决方案:
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
}
}
如果您希望您的函数 a) 接受数组并且 b) 类似于标准库函数,我看不到任何其他方法,只能返回“更改”的迭代器。我知道的唯一真正改变传递的迭代器的库函数是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*
右值,并且不能绑定到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);
}
然后,您可以使用各种左值和右值组合来调用它:
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;
}
但是请注意:当传递一个右值(例如数组或类似的表达式&local_var
)时,调用将起作用并且不会有未定义的行为,但是当然局部变量或数组的地址当然仍然不会改变。因此,在这种情况下,调用者无法找出该函数能够处理多少个字符。