Template working with std::string and char []

huangapple go评论74阅读模式
英文:

Template working with std::string and char []

问题

I wrote a function to trim strings. I want to use it with std::string and char[] type. I used template. When I use my function with string type everything is good, but I can't use it with char[]. My code is below:

template<typename T, typename Predicate>
T trimString(const T& str, Predicate pred) {
    auto left = std::find_if_not(str.begin(), str.end(), pred);
    auto right = std::find_if_not(str.rbegin(), str.rend(), pred);
    return T(left, right.base());
}


int main() {
    std::string text = "      123 example      ";
    //char text[] = "      123 example      ";
    std::cout << text << std::endl;
    std::cout << trimString(text, isspace) << std::endl;
    return 0;
}

When I use it with char[], I have these errors:

Severity Code Description Project File Line
Error (active) E0304 no instance of function template "trimString" matches the argument list Task3.exe
Severity Code Description Project File Line
Error C2672 'trimString': no matching overloaded function found
Severity Code Description Project File Line
Error (active) E0304 no instance of function template "trimString" matches the argument list Task3.exe
英文:

I wrote a function to trim strings. I want to use it with std::string and char[] type. I used template. When I use my function with string type everything is good, but I can't use it with char []. My code is below:

template&lt;typename T, typename Predicate&gt;
T trimString(const T&amp; str, Predicate pred) {
    auto left = std::find_if_not(str.begin(), str.end(), pred);
    auto right = std::find_if_not(str.rbegin(), str.rend(), pred);
    return T(left, right.base());
}


int main() {
    std::string text = &quot;      123 example      &quot;;
    //char text[] = &quot;      123 example      &quot;;
    std::cout &lt;&lt; text &lt;&lt; std::endl;
    std::cout &lt;&lt; trimString(text, isspace) &lt;&lt; std::endl;
    return 0;
}

When I use it with char [] I have this errors:

Severity	Code	Description	Project	File	Line
Error (active)	E0304	no instance of function template &quot;trimString&quot; matches the argument list	Task3.exe
Severity	Code	Description	Project	File	Line
Error	C2672	&#39;trimString&#39;: no matching overloaded function found
Severity	Code	Description	Project	File	Line
Error (active)	E0304	no instance of function template &quot;trimString&quot; matches the argument list	Task3.exe

答案1

得分: 1

忽略为何你的代码无法编译,你实际的 设计问题 在于这里:

return T(...

如果你拿到一个类型为 char[10] 的对象,从前面截掉 2 个字符,你希望返回一个 char[10] 吗?不,你不希望。你想要返回八个字符。

也就是说,无论你传入的是 std::stringstd::string_viewstd::array<char, N>std::span<char, -1>std::vector<char> 还是 char[N],你始终希望返回一个字符缓冲区,其大小只有在运行时才能确定,当你真正知道截去了多少时。

方便的是,C++ 一个动态大小的字符缓冲区,它叫做 std::string

所以最好将

template <typename T, typename Predicate>
T trimString(const T &str, Predicate pred)
{
    auto left = std::find_if_not(str.begin(), str.end(), pred);
    auto right = std::find_if_not(str.rbegin(), str.rend(), pred);
    return T(left, right.base());
}

改为

template <typename T, typename Predicate>
std::string trimString(const T &str, Predicate pred)
{
    auto left = std::find_if_not(str.begin(), str.end(), pred);
    auto right = std::find_if_not(str.rbegin(), str.rend(), pred);
    return std::string(left, right.base());
}

...除非。

除非 - 你将这个写成了一个模板,这样你的代码可以处理多种类型的字符缓冲区。然后,你立即调用了 .begin,因此它只对实现了 .begin 的字符缓冲区有效。

幸运的是,这是一个已解决的问题 - 你并不是第一个认为我们可以泛化不同类型的字符缓冲区的人:

template<typename Predicate>
std::string trimString(std::string_view str, Predicate pred)
{
    auto left = std::find_if_not(str.begin(), str.end(), pred);
    auto right = std::find_if_not(str.rbegin(), str.rend(), pred);
    return std::string(left, right.base());
}

这应该解决整个设计问题。(关于函数内部是否工作正常,我还没有检查。)

英文:

Disregarding why your code doesn't compile, your actual design problem is here:

return T(...

If you take a type char[10] and trim 2 off the front, do you want to return a char[10]? No, you do not. You want to return eight chars.

That is to say, it doesn't matter whether you are called with a std::string, a std::string_view, a std::array&lt;char,N&gt;, a std::span&lt;char,-1&gt;, a std::vector&lt;char&gt; or a char[N], you always want to return a char buffer whose size can only be determined at runtime when you actually know how much was trimmed away.

Conveniently, C++ has a dynamically sized char buffer, it's called std::string.

So it would be best to change

template &lt;typename T, typename Predicate&gt;
T trimString(const T &amp;str, Predicate pred)
{
    auto left = std::find_if_not(str.begin(), str.end(), pred);
    auto right = std::find_if_not(str.rbegin(), str.rend(), pred);
    return T(left, right.base());
}

into

template &lt;typename T, typename Predicate&gt;
std::string trimString(const T &amp;str, Predicate pred)
{
    auto left = std::find_if_not(str.begin(), str.end(), pred);
    auto right = std::find_if_not(str.rbegin(), str.rend(), pred);
    return std::string(left, right.base());
}

...except.

Except - you're writing this as a template, so your code can work on multiple types of char buffers. And then, you are immediately calling .begin, so it only works on char buffers that implement .begin.

Thankfully, this is a solved problem - you are not the first person who thought that we could generalize over different types of char buffer:

template&lt;typename Predicate&gt;
std::string trimString(std::string_view str, Predicate pred)
{
    auto left = std::find_if_not(str.begin(), str.end(), pred);
    auto right = std::find_if_not(str.rbegin(), str.rend(), pred);
    return std::string(left, right.base());
}

That should solve the whole of the design problem. (Whether the internals of the function work, I haven't checked.)

huangapple
  • 本文由 发表于 2023年5月7日 06:41:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76191494.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定