tags:

views:

117

answers:

4

For convenience, I'd like to be able to cast between two types defined in other libraries. (Specifically, QString from the Qt library and UnicodeString from the ICU library.) Right now, I have created utility functions in a project namespace:

namespace MyProject {
    const icu_44::UnicodeString ToUnicodeString(const QString& value);
    const QString ToQString(const icu_44::UnicodeString& value);
}

That's all well and good, but I'm wondering if there's a more elegant way. Ideally, I'd like to be able to convert between them using a cast operator. I do, however, want to retain the explicit nature of the conversion. An implicit conversion should not be possible.

Is there a more elegant way to achieve this without modifying the source code of the libraries? Some operator overload syntax, perhaps?

+4  A: 

You could always do exactly what you're doing but make it look more like casting. There may even be some reasonable argument for doing so, such as being able to override for more types and retain the same syntax.

Consider:

template < typename DestType, typename SourceType >
DestType string_cast(SourceType const& source)
{
  return string_cast_impl<DestType,SourceType>::apply(source);
}

template < typename DestType, typename SourceType >
struct string_cast_impl;

template < >
struct string_cast_impl<QString,icu_44::UnicodeString>
{
  QString apply(icu_44::UnicodeString const& val) { return MyProject::ToQString(value); }
};

// etc...

You might consider not using the impl struct (because you don't need to partially specialize...ever), or you might consider enhancing it so that you can use enable_if. At any rate, you'd have a common interface for string type conversion such that you don't need to remember what function to call...just call string_cast<Dest>(source).

Edit: come to think of it, I'm doing what you're doing in one of my projects to convert from std::string to/from std::wstring. I think I'll use this alternative to replace that.

Noah Roberts
A: 

A possible solution would be to wrap these types and provide explicit conversion constructors. I take it you cannot modify the source of both QString and icu_44::UnicodeString which would be the most natural place for the conversion constructors to reside. The use of the keyword explicit prohibits implicit conversion, hence conversions can only occur when you write QString converted(original) with original a value of typeicu_44::UnicodeString or vice versa.

The only problem with this approach is that you have to wrap your data types. I don't know whether you'll ever need more operations on these types currently not provided in the actual libraries or not, but if that's the case, wrapping is a possible way to go

Pieter
+1  A: 

If what you're striving for is to be able to say

QStrign qs;
UnicodeString us(qs);

or

UnicodeString us;
QString qs(us);

then no, you can't do that unless you can change either of the classes. You can, of course, introduce a new string:

NewString ns;
UnicodeString us(ns);
QString qs(us);

NewString nsus(us);
NewString nsqs(qs);

I'm not sure about this approach's elegance though, compared with your two explicit conversion functions.

wilhelmtell
Thanks; I was just curious if there was something in the language I was missing. Looks like the original way is about as simple as you can get.
Dave
A: 

Side question, do you mean to use the 4.4 namespace directly and not just icu::UnicodeString ?

Steven R. Loomis
I haven't really figured out the ICU namespace thing. I am compiling with -DU_USING_ICU_NAMESPACE=0 but still can refer directly to UnicodeString (without a namespace) in my code, and it works fine. But I also can use icu_44::UnicodeString (but not icu::UnicodeString). I'm using the icu_44::UnicodeString because perhaps the other is an older library? Not sure. Still working on that one....
Dave
Mapping icu to icu_44 is a function of symbol renaming. If you compile with -DU_DISABLE_RENAMING=1 ( or use the --disable-renaming option to configure ) then that won't happen. This affects symbols. The other isn't an older library. I'd just refer to UnicodeString without a namespace, and leave the renaming as-is.
Steven R. Loomis