【问题标题】:Is it possible to write one function for std::string and std::wstring?是否可以为 std::string 和 std::wstring 编写一个函数?
【发布时间】:2016-06-16 12:19:26
【问题描述】:

我刚刚为 std::string 编写了一个简单的实用函数。然后我注意到如果std::stringstd::wstringstd::u32string,该函数看起来完全一样。是否可以在这里使用模板功能?我对模板不是很熟悉,std::stringstd::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 函数(如查找、替换、擦除等)的一般概念。

【问题讨论】:

  • 我看不出有什么特别的错误。对我来说,我们的模板看起来不错。使用某些特定功能没有问题。如果你给一个没有在模板中使用函数的参数,它就不会编译
  • findreplace 需要一些技巧,因为字符类型不同。例如,上面的函数不适用于std::wstring,因为std::wstring::find_first_not_of 不采用const char*,而是采用const wchar_t*
  • 除了unsigned int 之外,我建议使用typename StdStringClass::size_type 或者如果启用了c++11,则使用auto。
  • @Benjamin 也许搜索到的字符串" \t\n" 应该换成StdStringClass(" \t\n"),它解决了吗?
  • @Radek:不,因为那会尝试调用wstring 不存在的构造函数。

标签: c++ string templates stl stdstring


【解决方案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;
}

【讨论】:

  • 请进一步详细说明并添加一些代码来说明您的答案。现在这不是一个有用的答案,因为它没有为 OP 问题提供明确的解决方案。
  • 假设我理解正确,我看不出这会如何减少代码重复。在课堂上,我仍然需要为每种类型的字符串实现上述代码。我的目标是坚持 DRY 原则。对我来说,使用一种模板方法似乎更优雅。
  • Fabian,@Revolver_Ocelot,我编辑了答案并添加了说明性代码。 Fabian,是的,我知道有一些额外的代码,但好处是您可以获得控制权。干杯!
  • (1) 这段代码不会编译(语法错误,构造函数中没有实际的函数调用)(2) 这比简单调用模板函数有什么好处?
  • @Revolver_Ocelot 它是not 更好 ,它只是添加了控制,以便您在任何时候想要避免运行时错误。
【解决方案2】:

这是一个好主意,但我会在 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);
}

我也会在 favro 中放弃 MSDN 风格的“inout”符号,以使用更简单的名称,例如 str。程序员自己会猜测str 结果,因为它作为非常量引用传递并且函数返回void

另外,我将unsigned int 更改为auto。所有标准 C++ 容器/字符串在返回索引时都返回 size_tsize_t 可能不是 unsigned intauto 将自身与正确的返回值相匹配。

【讨论】:

  • T(0) 应该是 T(' ') 吗?
  • 它应该是空终止符。再看我忘了空格,我会添加它
  • 我明白了。很好的答案。不幸的是,我无法使用 C++11。我希望能够绕过auto。前段时间我使用size_t 时gcc 编译器报错,因此我切换到unsigned int
  • 您仍然可以使用 C++03 来完成。而不是constexpr auto... 只需写const Tstd::basic_string&lt;T&gt;::size_type 其余部分
  • 我建议不要在此处明确使用basic_string,并且有一个很好的理由:如果我稍后切换到提供我在这里使用的接口的替代字符串类怎么办?我会使用typename StringType 并使用StringType::value_type 来获取其基础字符类型。话虽如此,使用某种形式的isspace 谓词而不是硬编码的空白列表可能会更好。特别是如果使用像 wstring 这样的东西(暗示不仅仅是 ASCII 空白字符)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-12
相关资源
最近更新 更多