2012-03-23 1 views
1

UPDATE:Возможно ли, чтобы метод C++ принимал либо const char *, либо const wchar_t * в качестве параметра без перегрузки метода?

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

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++, и я не могу вспомнить ++ пути C идти об этом:

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

+0

Ugh! Здесь не так много C++. –

ответ

3

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

+0

Я пробовал подход к шаблону (см. Мое обновление), но затем мне пришлось использовать if-инструкцию для определения типа и все еще компилятор, жалующийся на тип, в зависимости от того, какая из ветвей не была занята, поэтому мне пришлось засорять код приложением. Я просто не делаю это правильно? – SaldaVonSchwartz

+2

@SaldaVonSchwartz: Если вам нужно определить тип внутри функции шаблона, тогда шаблон не подходит. Вы должны придерживаться функций перегрузки. –

1

Вы можете использовать перегрузку метода. Я также предложил бы использовать 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

Передача строки по const referenec может быть немного лучше, чем у пользователя –

+0

Вот почему рекомендую это как предложение. Использование «const char *» или «const wchar_t *» тоже прекрасное. 'std :: string' и' std :: wstring' - это просто способ C++ для обработки этих типов. – Joe

+0

мой комментарий был более тем, что если вы используете строку, используйте их правильно, иначе передайте их по ссылке const в качестве функции, чтобы избежать бесполезных копий. –

2

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

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

Да, но мое тело метода нуждается в длине str, и оказывается, что вы не можете использовать одну и ту же функцию, чтобы получить длину как char *, так и char_t *. Например, мне нужно было бы strlen (str) и wcslen (str) – SaldaVonSchwartz

+0

Вы могли написать перегруженную функцию-обертку для вычисления длины. Затем в совокупных функциях (например, 'someFunction') вызывается так: это позволит вам только однократно записывать агрегированные функции, что может быть еще более экономичным, если у вас есть более агрегированные функции, чем обертки для различных функций обработки строк. – Attila

3

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

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

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

Вы также можете использовать шаблоны. Если код не изменяет между полукокса и 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 и полукокса с помощью перегрузки или, специализирующимся, затем шаблоны позволяют построить на вершине, что при наличии единой версии для обоих типов с помощью перегруженных 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 
    } 
} 
+0

правый .. но изготовление шаблон специализация фактически записывает два метода. Я имею в виду, в чем разница между перегрузкой foo (const char * str) и foo (const char_t * str) по сравнению с шаблоном void foo (CharT const * c); шаблона <> недействительными Foo (символ сопз * с) {/ * символ версия * /} шаблона <> недействительными Foo (wchar_t сопз * с) {/ * wchar_t версия * /} – SaldaVonSchwartz

+0

перегрузки влечет за собой запись в методы с очень похожие тела, шаблоны тоже (ваш пример), и единственным другим подходом является шаблон с операциями if, которые проверяют тип, который кажется взломанным. – SaldaVonSchwartz

+0

@SaldaVonSchwartz. Существует просто нет возможности обойти создание двух тел функций, если функция тела должны быть разными, независимо от того, используете ли вы перегрузку или специализацию. Если вы определяете различия между телами функций, используя либо перегрузку, либо специализацию, вы можете написать основную функцию как один шаблон (т.нет специализации). – bames53

0

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

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 Или использовать.

 Смежные вопросы

  • Нет связанных вопросов^_^