1

UPDATE:

I went for the template approach cause it seemed the most elegant / concise but then I end up with stuff like this:

template<typename charType>
    int doSomethingWithString(const charType* buffer)
    {
        wchar_t* tempBuffer = NULL;

        if(typeid(charType) == typeid(char))
        {
            tempBuffer = (wchar_t*)malloc(sizeof(wchar_t)*strlen((char*)buffer));
            mbstowcs(tempBuffer, (const char*)buffer, strlen((const char*)buffer));
        }
        else if(typeid(charType) == typeid(wchar_t))
        {   tempBuffer = (wchar_t*)malloc(sizeof(wchar_t)*strlen((char*)buffer));
            tempBuffer = wcscpy(tempBuffer, (const wchar_t*)buffer);
        }

At which point I feel it's kind of ugly (specially since I still have to have all those casts there to let the compiler know). I also tried turning the parameter into a wstring but I just don't seem to find an appropriate constructor for both cases?

It's been a while now that I've been away from C++ and I can't remember the C++ way of going about this:

Let's say I have a class with some method myClass::doSomethingWithString(...) and I want the same method to be able to be called passing in a character sequence as either const char* or const wchar_t*. Was there a way to make the method be able to accept both types of "strings" and tell if the parameter is const char* or const wchar_t* inside the method implementation? Or is method overloading the only way to go about it?

SaldaVonSchwartz
  • 3,769
  • 2
  • 41
  • 78

5 Answers5

3

Method overloading is the only way to go about it.
Alternately, You could write a single template function.However, in that case the actions you perform inside the function would have to be same in either case. In this case the compiler will generate source code of the functions for your both the types.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • I tried the template approach (see my update) but then I ended up with a need for an if-statement to determine the type and still the compiler complaining about the type in whichever happens to be the branch not taken, so I had to litter the code with casts. Am I just not doing it right? – SaldaVonSchwartz Mar 24 '12 at 08:10
  • 2
    @SaldaVonSchwartz: If you need to determine the type inside the template function, then template is not the right approach.You should stick to overloading functions. – Alok Save Mar 24 '12 at 08:26
3

Overloading is probably the best way to go about it, unless you're using another API that allows exactly the same syntax with both char* and wchar_t*.

void foo(char const *c) {
    std::cout << c << '\n';
}

void foo(wchar_t const *c) {
    std::wcout << c << L'\n';
}

You could also use templates. If the code doesn't actually change between char and wchar_t versions then you'll only have one version:

template<typename CharT>
void foo(CharT const *c) {
    std::cout << "foo called\n";
}

But since doing anything useful usually involves using the argument, and using the argument usually requires different code (e.g. calling printf for char and wprintf for wchar_t) you'll have to have a version for each type. With a template you'd do that by specializing.

template<typename CharT>
void foo(CharT const *c);

template<> void foo<char>(char const *c) { /* char version */ }
template<> void foo<wchar_t>(wchar_t const *c) { /* wchar_t version */ }

Now, if you have an API that provides an identical interface for wchar_t and char via overloading or specializing, then templates let you build on top of that by having a single version for both types using the overloaded API:

// Given the above overloads/template specializations:
template<typename CharT>
void bar(CharT const *c) {
    foo(c); // calls foo(char const *) or foo(wchar_t const *) as needed.
}

But since you're asking if there's a way to tell inside the function what the type is, it seems likely that you want to have different versions. In which case you're probably best off using overloads, or factoring the differences out into overloaded functions so the main function can be a single template.

There is another option that's probably a bad idea. Depending on the actual differences you might be able to have a single template and then do something like:

template<typename T>
int foo(T const *t) {
    if(sizeof T == sizeof wchar_t) {
        // wchar_t version
    } else {
        // char version
    }
}

And someday C++ may adopt static_if in which case you'll be able to do:

template<typename T>
int foo(T const *t) {

    static_if(std::is_same<T,wchar_t>::value) {
        // wchar_t version
    }

    static_if(std::is_same<T,char>::value) {
        // char version
    }
}
bames53
  • 86,085
  • 15
  • 179
  • 244
  • right.. but doing template specialization is essentially writing two methods. I mean, what's the difference between having overloaded foo(const char* str) and foo (const char_t* str) versus template void foo(CharT const *c); template<> void foo(char const *c) { /* char version */ } template<> void foo(wchar_t const *c) { /* wchar_t version */ } – SaldaVonSchwartz Mar 24 '12 at 20:55
  • overloading entails writing to methods with very similar bodies, templates does too (your example) and the only other approach is a template with if statements inside checking for type which seems like a hack.. – SaldaVonSchwartz Mar 24 '12 at 20:57
  • @SaldaVonSchwartz There's just no way to get around writing two function bodies _if the function bodies have to be different_, whether you use overloading or specialization. If you factor out the differences between the function bodies, using either overloading or specialization, then you can write the primary function as a single template (i.e. no specialization). – bames53 Mar 25 '12 at 00:59
  • yeah I also tried the core function as a template private method or straight-out function and that works.. but now I'm thinking, wouldn't it be better at this point to just have the class internally use only one type, say wstring (since after all we are in C++ so why not encourage objects) and then the const char* public method merely creates a const char_t* and calls the const char_t* version and this version in turn creates a wstring and calls the interal core stuff of the class (since I proposed the class only deal with string objects internally) ? – SaldaVonSchwartz Mar 26 '12 at 23:55
2

char and wchar_t are different types, so are the pointers to them. Thus you cannot write one function that accepts both as there is no common "parent" (so to speak).

YOu can write a template function that accepts the type as a template parameter. In that case you still have two functionsin your binary program if you call it both with char* and wchar_t*, but in the cose you will see only one function body.

template<T> void someFunction(T* str) {
  // your code here.  Use T when you would use char or wchar_t in a regular function
}
Attila
  • 28,265
  • 3
  • 46
  • 55
  • yeah but my method body needs the length of str, and it turns out that you can't use the same function to get the length of both a char* and a char_t*. For example I'd have to have strlen(str) and wcslen(str) – SaldaVonSchwartz Mar 24 '12 at 20:52
  • You could write an overloaded wrapper function to calculate the length. Then in aggregate functions (like `someFunction`) call that -- this would allow you to only write the aggregate functions once, which might still be more economical if you have more aggregate functions than the wrappers for the different string handling functions. – Attila Mar 24 '12 at 22:15
1

You can use method overloading. I would also suggest using std::string and std::wstring for C++.

Example:

class MyClass
{
public:
    void doSomethingWithString(std::string s)
    {
        std::cout << "String: " << s << std::endl;
    }
    void doSomethingWithString(std::wstring ws)
    {
        std::wcout << L"Wide String: " << ws << std::endl;
    }
};

...

    MyClass myClass;
    myClass.doSomethingWithString("const char *");
    myClass.doSomethingWithString(L"const wchar_t *");
Joe
  • 56,979
  • 9
  • 128
  • 135
  • passing string by const referenec could be a bit better performance wise – Joel Falcou Mar 23 '12 at 20:59
  • That is why recommend it as a suggestion. Using a 'const char *' or 'const wchar_t *' is fine as well. `std::string` and `std::wstring` is just the C++ way to handle those types. – Joe Mar 23 '12 at 21:04
  • my comment was more that if you use string, use them properly aka pass them by const reference as functiona rgument to avoid useless copies. – Joel Falcou Mar 24 '12 at 07:56
0

Write a class that has implicit constructors for both kinds of arguments:

struct String {
  String(const char*): called_with_wchar_t(false) { }
  String(const wchar_t*): called_with_wchar_t(true) { }
  bool called_with_wchar_t;
};

void function(const String&);
...
function("a");
function(L"a");

Or use Boost.Variant.

Philipp
  • 48,066
  • 12
  • 84
  • 109