英文:
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<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 this 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
答案1
得分: 1
忽略为何你的代码无法编译,你实际的 设计问题 在于这里:
return T(...
如果你拿到一个类型为 char[10]
的对象,从前面截掉 2 个字符,你希望返回一个 char[10]
吗?不,你不希望。你想要返回八个字符。
也就是说,无论你传入的是 std::string
、std::string_view
、std::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<char,N>
, a std::span<char,-1>
, a std::vector<char>
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 <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());
}
into
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());
}
...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<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());
}
That should solve the whole of the design problem. (Whether the internals of the function work, I haven't checked.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论