C++ - 如何将函数转换为模板函数

Bre*_*ett 2 c++ c++11

我有一个C++函数,它采用逗号分隔的字符串并拆分为一个std::vector<std::string>

std::vector<std::string> split(const std::string& s, const std::string& delim, const bool keep_empty = true) {

    std::vector<std::string> result;
    if (delim.empty()) {
        result.push_back(s);
        return result;
    }
    std::string::const_iterator substart = s.begin(), subend;
    while (true) {
        subend = std::search(substart, s.end(), delim.begin(), delim.end());
        std::string temp(substart, subend);
        if (keep_empty || !temp.empty()) {
            result.push_back(temp);
        }
        if (subend == s.end()) {
            break;
        }
        substart = subend + delim.size();
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

但是,我真的希望能够将此函数应用于多种数据类型。例如,如果我有输入std::string

1,2,3,4,5,6
Run Code Online (Sandbox Code Playgroud)

然后我希望函数的输出是ints的向量。我对 相当陌生C++,但我知道有一种叫做template类型的东西,对吧?是否可以将此函数创建为通用模板?还是我误解了template函数的工作原理?

Sho*_*hoe 5

您可以将模板函数声明为:

template<class ReturnType>
std::vector<ReturnType> split(const std::string&, const std::string&, const bool = true);
Run Code Online (Sandbox Code Playgroud)

然后将其专门用于您想要允许的每种向量类型:

template<>
std::vector<std::string> split(const std::string& s, const std::string& delim, const bool keep_empty) {
    // normal string vector implementation
}

template<>
std::vector<int> split(const std::string& s, const std::string& delim, const bool keep_empty) {
    // code for converting string to int
}

// ...
Run Code Online (Sandbox Code Playgroud)

您可以在此处阅读有关 string 到 int 的转换的信息

然后,您需要调用split

auto vec = split<int>("1,2,3,4", ",");
Run Code Online (Sandbox Code Playgroud)

  • 这是一个好的开始。但是,对于您的解决方案,您必须为要处理的每种类型复制和调整所有代码。与传统的函数重载相比,这种方法有什么好处?不是更多关于使用模板以避免这种重复的问题吗? (2认同)

Woj*_*wka 5

你可以“模板化”这个函数——要启动它,你只需要在函数之前std::vector<std::string>用 'std::vector and addtemplate`替换。但是您需要注意如何将字符串放入结果向量中。在您当前的实现中,您只有

result.push_back(temp);
Run Code Online (Sandbox Code Playgroud)

因为result是字符串向量,而 temp 是字符串。在一般情况下,虽然这是不可能的,但如果您想将此函数与例如vector<int>此行一起使用,则将无法编译。然而,这个问题可以用另一个函数轻松解决 - 再次模板 - 它将字符串转换为您想要使用的任何类型split。让我们调用这个函数convert

template<typename T> T convert(const std::string& s);
Run Code Online (Sandbox Code Playgroud)

然后您需要为您需要的任何类型提供此功能的专业化。例如:

template<> std::string convert(const std::string& s) { return s; }
template<> int convert(const std::string& s) { return std::stoi(s); } 
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您不需要像其他答案所建议的那样专门化整个函数,只需要根据类型来专门化部分。应该对线路做同样的事情

result.push_back(s);
Run Code Online (Sandbox Code Playgroud)

在没有分隔符的情况下。