使用for_each迭代NULL终止的字符串是可能的:
const char *name = "Bob";
void func(const char &arg)
{
cout << arg;
}
int main()
{
for_each(name, name + strlen(name), func);
}
类似于NULL终止的字符串列表(不必首先确定列表的总长度),例如:
const char *names[] = { "Bob", "Adam", "Simon", NULL };
答案 0 :(得分:8)
std :: for_each在一个范围内“迭代”,因此要将它与不确定长度的数组一起使用,您需要使用自定义迭代器来指示数组的结尾(在NULL成员上)。如果你坚持使用以NULL结尾的char *数组,你当然可以为它创建自己的for_each函数,例如:
template <typename Function>
void for_each_in_null_terminated_cstring_array(const char** array, Function f)
{
while (*array) {
f(*array);
array++;
}
}
const char *names[] = { "Bob", "Adam", "Simon", NULL };
for_each_in_null_terminated_cstring_array(names, func);
但我并不是真的推荐这个解决方案。
编辑:是的,更通用的总是更多更好,不是吗?
template <typename T, typename Function>
void for_each_in_null_terminated_array(T* array, Function f)
{
while (*array) {
f(*array);
array++;
}
}
(这里是我之前提到的null终止(“false”-terminated)迭代器的实现 - 根据以下建议进行了一两次更改。它应该是一个真正的InputIterator)
template <class T>
class nt_iterator: public std::iterator<std::input_iterator_tag, T>
{
public:
typedef typename nt_iterator<T>::pointer pointer;
typedef typename nt_iterator<T>::value_type value_type;
nt_iterator(): p(), pte(true) {}
nt_iterator(pointer p_): p(p_), pte(!p_) {}
nt_iterator(const nt_iterator<T>& rhs): p(rhs.p), pte(rhs.pte) {}
nt_iterator<T>& operator++() {
++p;
if (!*p) pte = true; // once past-the-end, always past-the-end
return *this;
}
nt_iterator<T> operator++(int) {
nt_iterator n(*this);
operator++();
return n;
}
bool operator==(const nt_iterator<T>& rhs) {
return pte && rhs.pte || p == rhs.p;
}
bool operator!=(const nt_iterator<T>& rhs) {
return !(operator==(rhs));
}
value_type operator*() { return *p; }
private:
pointer p;
bool pte; // past-the-end flag
};
它是如何使用的:
void print(const char* str);
int main()
{
const char* array[] = {"One", "Two", "Three", NULL, "Will you see this?"};
std::for_each(nt_iterator<const char*>(array),
nt_iterator<const char*>(),
print);
}
它可能比循环版本慢一些,因为等价检查的数量增加 - 与例如打印文本相比,速度差异当然是微不足道的 - 但是应该注意std::for_each
做< em> not 神奇地使循环更快(实际上,您可能会惊讶地看到您的编译器供应商如何定义函数 - 也就是说,如果您期望太多)。
答案 1 :(得分:3)
用
const char *names[] = { "Bob", "Adam", "Simon" };
你可以打电话
std::for_each(names, names + sizeof(names)/sizeof(names[0]), func );
或更好,使用two helper functions:
std::for_each(begin(names), end(names), func );
当然,这在数组衰变成指针的时刻失败了(但至少编译器不接受它)。如果必须依赖于尾随NULL
,您需要编写自己的循环函数或事先计算,与std::strlen()
一样:
std::ptr_diff_t num = std::find( names
, names + std::numeric_limits<std::size_t>::max()
, NULL);
std::for_Each( names, names+num, func );
答案 2 :(得分:3)
扩展Basilevs,回答一个完全有效的解决方案。
自定义迭代器可以定义如下:
template <class T>
class NullTerminatedIterator
:public std::iterator<std::forward_iterator_tag,
T,ptrdiff_t,const T*,const T&>
{
public:
typedef NullTerminatedIterator<T> NTI;
NullTerminatedIterator(T * start): current(start) {}
NTI & operator++() {current++; return *this;}
T & operator*() { return *current; }
static NTI end() { return NTI(0); }
bool operator==(const NTI & that) { return *current == *that.current; }
bool operator!=(const NTI & that) { return *current != *that.current; }
private:
T * current;
};
然后像这样使用:
const char *names[] = {"Bob", "Adam", "Simon", NULL};
NullTerminatedIterator<char*> iter((char**)names);
for_each(iter, NullTerminatedIterator<char*>::end(), func);
NullTerminatedIterator的基类取自此custom iterator个问题。
这仅在for_each调用期间根据请求遍历列表。
答案 3 :(得分:1)
有多个答案可以告诉您可以做什么。然而,你的特定问题的答案只是“不,你不能”:)
答案 4 :(得分:0)
您可以将sizeof()用于编译时大小的数组。
const char *names[] = { "Bob", "Adam", "Simon" };
std::for_each(names, names + sizeof(names)/sizeof(*names), [](const char* arg) {
std::cout << arg << "\n";
});
std::cin.get();
对于动态大小的数组,您应该使用std::vector<std::string>
并迭代它。
请原谅我使用lambdas,你的编译器(可能)不支持它们。
答案 5 :(得分:0)
将它们添加到容器中,并使用for_each迭代它们 我在我的例子中使用了一个向量:
void function(string name)
{
cout << name;
}
int main()
{
vector<string> nameVector;
nameVector.push_back("Bob");
nameVector.push_back("Adam");
nameVector.push_back("Simon");
for_each(nameVector.begin(), nameVector.end(), function);
return 0;
}
答案 6 :(得分:0)
为了达到你想要的效果,你能不能通过引用指向const char的指针替换传递给func的参数。有点像这样:
const char *names[] = { "Bob", "Adam", "Simon" };
void func( const char* &arg )
{
cout << arg << endl;
}
int main()
{
for_each( names,
names + sizeof( names ) / sizeof( names[ 0 ] ),
func );
}
显然对于以NULL结尾的字符串数组,只需从数组大小中减去1 ...
答案 7 :(得分:0)
template <class T>
struct NullTerminatedIterator {
typedef NullTerminatedIterator<T> NTI;
T * current;
NTI & operator++() {current++; return this;}
T & operator*() {return *current;}
NullTerminatedIterator(T * start): current(start) {}
static NTI end() {return NTI(0);}
bool operator==(const NTI & that) {return current==that.current;}
}
答案 8 :(得分:0)
我知道这不是for_each,但我想使用旧的常规for循环来做同样的事情。这个来自MSDN blog:
重新解释一个双重空终止的字符串,实际上是一个带有空字符串作为终结符的字符串列表,这使得编写代码可以非常简单地遍历一个以双空终止的字符串:
for (LPTSTR pszz = pszzStart; *pszz; pszz += lstrlen(pszz) + 1) {
// ... do something with pszz ...
}
对我来说看起来很干净!
答案 9 :(得分:0)
// C version
const char* vars[16]={"$USER","$HOME","$DISPLAY","$PASSWORD",0};
for(const char** pc = vars; *pc!=0; pc++)
{
printf("%s",*pc);
}