2016-03-03 4 views
10

Я просто написал простую функцию утилиты для std :: string. Затем я заметил, что функция будет выглядеть точно так же, если std::string был std::wstring или std::u32string. Можно ли использовать здесь функцию шаблона? Я не очень хорошо знаком с шаблонами, и std::string и std::wstring являются самими шаблонами, что может быть проблемой.Можно ли написать одну функцию для std :: string и std :: wstring?

template<class StdStringClass> 
inline void removeOuterWhitespace(StdStringClass & strInOut) 
{ 
    const unsigned int uiBegin = strInOut.find_first_not_of(" \t\n"); 

    if (uiBegin == StdStringClass::npos) 
    { 
    // the whole string is whitespace 
    strInOut.clear(); 
    return; 
    } 

    const unsigned int uiEnd = strInOut.find_last_not_of(" \t\n"); 
    strInOut = strInOut.substr(uiBegin, uiEnd - uiBegin + 1); 
} 

Это правильный способ сделать это? Есть ли подводные камни с этой идеей. Я не говорю об этой функции, но общая концепция использования шаблонного класса StdStringClass и вызов обычных функций std::string, таких как поиск, замена, стирание и т. Д.

+1

I не вижу ничего особенного. Для меня наш шаблон кажется хорошим. Нет проблем с использованием определенной функции. Он просто не компилируется, если вы указываете параметр, который не использовал функцию внутри шаблона – Garf365

+1

'find' и' replace' потребует некоторой обманки, так как типы символов различаются. Например, вышеприведенная функция не будет работать для 'std :: wstring', потому что' std :: wstring :: find_first_not_of' не принимает 'const char *', а 'const wchar_t *'. –

+1

Seem отлично подходит для меня, кроме как вместо 'unsigned int', я бы рекомендовал использовать' typename StdStringClass :: size_type' или auto, если включен C++ 11. – Radek

ответ

6

Это хорошая идея, но я бы построил шаблон сверху из std::basic_string, а затем общего StdStringclass

template<class T> 
inline void removeOuterWhitespace(std::basic_string<T>& strInOut) 
{ 
    constexpr auto delim[] = {T(' '),T('\t'),T('\n'),T(0)}; 
    const auto uiBegin = strInOut.find_first_not_of(delim); 

    if (uiBegin == std::basic_string<T>::npos) 
    { 
    // the whole string is whitespace 
    strInOut.clear(); 
    return; 
    } 

    const auto uiEnd = strInOut.find_last_not_of(delim); 
    strInOut = strInOut.substr(uiBegin, uiEnd - uiBegin + 1); 
} 

Я хотел бы также канаву MSDN-стиль «Inout» нотации в Фавро для простого имени, как str. программист догадается, что str: результат, поскольку он передается как неконстантная ссылка и функция возвращает void.

также, я изменил unsigned int до auto. все стандартные контейнеры/строки C++ возвращают size_t при возврате индексов. size_t не может быть unsigned int. auto соответствует самому правильному возвращаемому значению.

+0

Является ли 'T (0)' предполагается 'T ('')'? – Fabian

+0

он должен быть нулевым терминатором. снова посмотрев, я забыл пробел, я добавлю его –

+0

Я вижу. Очень хороший ответ. К сожалению, C++ 11 недоступен для меня. Я надеюсь, что смогу обойти «авто». Компилятор gcc жаловался, когда я использовал 'size_t' некоторое время назад, поэтому я переключился на' unsigned int'. – Fabian

-1

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

РЕДАКТИРОВАТЬ: добавлена ​​иллюстративная структура

EDIT2 один, который собирает (по крайней мере, с vs2015) :-)

class StringType1; 
class StringTypeN; 

class str { 

    //template function 
    template<class StdStringClass> 
    inline void removeOuterWhitespace(StdStringClass & strInOut) 
    { 
     //. 
     //. 
     //. 
    } 

public: 
    //constructors 
    str(StringType1 &s1) { removeOuterWhitespace(s1); } 
    //. 
    //. 
    //. 
    str(StringTypeN &sN) { removeOuterWhitespace(sN); } 


}; 

int main() { 

    return 0; 
} 

EDIT3 Доказательство концепции

#include <iostream> 
class incr { 
    //template function 
    template<class incrementor> 
    inline void removeOuterWhitespace(incrementor & n) 
    { 
     n++; 
    } 
public: 
    //constructors 
    incr(int &n1) { removeOuterWhitespace(n1); } 
    incr(double &n1) { removeOuterWhitespace(n1); } 
    incr(float &n1) { removeOuterWhitespace(n1); } 
}; 

int main() { 
    int n1 = 1; 
    double n2 = 2; 
    float n3 = 3; 
    std::cout << n1 << "\t" << n2 << "\t" << n3 << std::endl; 
    auto test1 = incr(n1); 
    auto test2 = incr(n2); 
    auto test3 = incr(n3); 
    //all variables modified 
    std::cout << "all variables modified by constructing incr" << std::endl; 
    std::cout << n1 << "\t" << n2 << "\t" << n3 << std::endl; 
    return 0; 
} 
+0

Просьба уточнить и добавить код, чтобы проиллюстрировать ваш ответ. Теперь это не очень полезный ответ, так как он не дает окончательного решения проблемы ОП. –

+0

Предполагая, что я правильно вас понимаю, я не вижу, как это уменьшит дублирование кода. В классе я все равно должен был бы реализовать вышеуказанный код для каждого типа строки. Моя цель - придерживаться принципа СУХОЙ. Использование одного метода шаблона кажется мне намного более изящным. – Fabian

+0

Fabian, @Revolver_Ocelot, я отредактировал ответ и добавил иллюстративный код. Фабиан, да, я знаю, что есть какой-то дополнительный код, но преимущество в том, что вы получаете контроль. ура! –

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

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