Возможно ли, чтобы метод C ++ принимал в качестве параметра const char * и const wchar_t * без перегрузки метода? - PullRequest
1 голос
/ 24 марта 2012

ОБНОВЛЕНИЕ:

Я остановился на шаблонном подходе, потому что он казался самым элегантным / лаконичным, но потом я получаю такие вещи:

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

В этот момент я чувствую, что это немного уродливо (тем более, что мне все еще нужны все эти приведения, чтобы компилятор знал).Я также пытался превратить параметр в строку wstring, но я просто не могу найти подходящий конструктор для обоих случаев?

Уже давно я не в С ++ и не могу вспомнитьC ++ способ сделать это:

Допустим, у меня есть класс с некоторым методом myClass :: doSomethingWithString (...), и я хочу, чтобы тот же метод можно было вызывать, передавая последовательность символов каклибо const char *, либо const wchar_t *.Был ли способ сделать метод способным принимать оба типа «строк» ​​и сообщать, является ли параметр const char * или const wchar_t * внутри реализации метода?Или перегрузка метода - единственный способ это сделать?

Ответы [ 5 ]

3 голосов
/ 24 марта 2012

Перегрузка, вероятно, является наилучшим способом решения этой проблемы, если только вы не используете другой API, который допускает точно такой же синтаксис как для char *, так и для wchar_t *.

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

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

Вы также можете использовать шаблоны.Если код фактически не меняется между версиями char и wchar_t, то у вас будет только одна версия:

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

Но поскольку для выполнения чего-либо полезного обычно требуется использование аргумента, а для использования аргумента обычно требуется другой код(например, вызов printf для char и wprintf для wchar_t) у вас должна быть версия для каждого типа.С шаблоном вы бы сделали это путем специализации.

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

Теперь, если у вас есть API, который предоставляет идентичный интерфейс для wchar_t и char посредством перегрузки или специализации, то шаблоны позволяют вам строить поверх этогоимея единую версию для обоих типов с использованием перегруженного 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.
}

Но так как вы спрашиваете, есть ли способ узнать внутри функции, что это за тип, кажется, что вы хотите иметьразные версии.В этом случае вам, вероятно, лучше всего использовать перегрузки или учесть различия в перегруженных функциях, чтобы основная функция могла быть одним шаблоном.

Есть еще один вариант, который, вероятно, является плохой идеей.В зависимости от реальных различий вы можете иметь один шаблон, а затем сделать что-то вроде:

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

И когда-нибудь C ++ может принять static_if, и в этом случае вы сможете сделать:

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 голосов
/ 24 марта 2012

Перегрузка метода - единственный способ сделать это.
В качестве альтернативы, вы можете написать одну шаблонную функцию. Однако в этом случае действия, которые вы выполняете внутри функции, должны быть одинаковыми в любом случае. В этом случае компилятор сгенерирует исходный код функций для обоих типов.

2 голосов
/ 24 марта 2012

char и wchar_t - это разные типы, так же как и указатели на них. Таким образом, вы не можете написать одну функцию, которая принимает оба, так как нет общего «родителя» (так сказать).

Вы можете написать функцию шаблона, которая принимает тип в качестве параметра шаблона. В этом случае у вас все еще есть две функции в вашей двоичной программе, если вы вызываете ее с помощью char* и wchar_t*, но в коде вы увидите только одно тело функции.

template<T> void someFunction(T* str) {
  // your code here.  Use T when you would use char or wchar_t in a regular function
}
1 голос
/ 24 марта 2012

Вы можете использовать метод перегрузки.Я бы также предложил использовать std::string и std::wstring для C ++.

Пример:

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 *");
0 голосов
/ 24 марта 2012

Напишите класс, который имеет неявные конструкторы для обоих типов аргументов:

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

Или используйте Boost.Variant .

...