c++ - Ambiguous template parameter -
i've created template function defined as
template < typename _iter8, typename _iter32 > int utf8toutf32 ( const _iter8 & _from, const _iter8 & _from_end, _iter32 & _dest, const _iter32 & _dest_end );
edited: first parameter const type.
the first , third parameters change reflect new position. second , fourth parameters mark upper boundary of iteration.
i'm hoping implement 'one functions fits all' logic. stipulation both _iter
types of same type , dereferenceable. want template parameters deducable.
the first problem encountered was
char utf8string [] "...some utf8 string ..."; wchar_t widestring [ 100 ]; char * piter = utfstring; utf8toutf16( piter, piter + n, widestring, widestring + 100 );
the _iter16
ambiguous. i'm guessing because compiler sees third parameter wchar_t[ 100 ] type
, fourth wchar_t* type
. correct me if i'm wrong. changing code to:
utf8toutf16( piter, piter + n, (wchar_t*)widestring, widestring + 100 );
fixes problem. ugly works.
then hit problem:
unsigned long ncodepoint; utf8toutf32( piter, piter + n, &ncodepoint, &ncodepoint + 1 ));
obviously, if changed ncodepoint
array type , applied same cast first, compile.
i'm not sure if defined template parameters wrong. question how correctly code given constraints above, , there way without resorting casts?
edit: jogojapan , dyp pointed out below, above cast shouldn't compile. should have instead created new pointer front of array , passed in. ncodepoint, may have create length 1 array.
as jogojapan gave answer, i'll make community wiki.
imo, adequate solution:
template < typename iter8, typename iter32 > iter32 utf8toutf32(iter8 _from, iter8 _from_end, iter32 _dest, iter32 _dest_end);
this intended return wanted _dest
change to.
if need return int
, return pair.
to reflect iterators read from, , written to, use naming scheme template parameters, e.g. inputiterator8
, outputiterator32
.
to give analogy function of standard library:
std::vector<int> v = {1,2,3,4}; for(auto = v.begin(); != v.end();) { if(*i == 2) { = v.erase(i); // iterator invalidated , new "next" iterator returned } }
if want function a) accept arrays , b) similar standard library functions, don't see other way return "changed" iterators. library function know changes iterator passed std::advance
.
example:
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) );
(edit jogojapan)
if must keep passing iterators references because want update text position pointing at, both problems described in question cannot solved directly.
problem 1: passing widestring
, local array, function mean type decays wchar_t*
rvalue, , cannot bound wchar_t *&
non-const reference. in other words, cannot have function modify address of local array. casting pointer not change fact, , compiler wrong when accepts solution.
problem 2: similarly, passing address of ncodepoint
reference impossible, address cannot changed. solution store address in separate pointer first, , pass that:
unsigned long *pcodepoint = &ncodepoint; utf8toutf32(piter,piter+5,pcodepoint,pcodepoint+1);
(another edit jogojapan)
if want pass reference, want make function flexible enough accept non-reference parameters well, can provide overloaded definitions of template:
/* using c++11 code convenience. rewriting in c++03 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); }
you can call kinds of combinations of 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; }
but warned: when passing rvalue (such array or expression &local_var
), call work , there no undefined behaviour, of course address of local variable or array of course still not change. caller won't, in situation, able find out how many characters function able process.
Comments
Post a Comment