Is it possible to have a C++ method accept either const char* and const wchar_t* as a parameter without overloading the method?

我是研究僧i 提交于 2019-12-02 11:32:45

问题


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?


回答1:


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.




回答2:


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
    }
}



回答3:


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
}



回答4:


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 *");



回答5:


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.



来源:https://stackoverflow.com/questions/9846318/is-it-possible-to-have-a-c-method-accept-either-const-char-and-const-wchar-t

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!