C++ range based loop with special case for first item?
I find myself often with code that looks like this:
bool isFirst = true;
for(const auto &item: items)
{
if(!isFirst)
{
// do something
}
// Normal processing
isFirst = false;
}
Seems like there ought to be better way to express this as it's a common pattern in functions that act like "join".
c++
|
show 1 more comment
I find myself often with code that looks like this:
bool isFirst = true;
for(const auto &item: items)
{
if(!isFirst)
{
// do something
}
// Normal processing
isFirst = false;
}
Seems like there ought to be better way to express this as it's a common pattern in functions that act like "join".
c++
That's why I'm sad thatbool
s don't have--
anymore...
– Quentin
11 hours ago
Shouldn't it beelse { /* Normal processing */ }
? In this case you can look at this answer (it skips the last element, the idea is similar): stackoverflow.com/a/35372958/2956272
– dyukha
11 hours ago
2
When my code requires special first-element action (which frankly, I could likely count on one hand the number of times I've needed that in the last five years and still have fingers left over), I don't use ranged-for. I use an iterator, and if-test, and a nested while loop thereafter. The only place that causes headache is when the action taken is a precursor and not an alternative (i.e. the model you're using is such a case: first element gets actions A+B, remaining elements get B, as opposed to first element gets A, remaining get B).
– WhozCraig
11 hours ago
4
Possible duplicate of Skipping in Range-based for based on 'index'?
– hlscalon
11 hours ago
1
Thanks everyone. I think the a @Ali who posted on stackoverflow.com/questions/21215947/…, had great points. Moving the special case outside of the loop is a much better idea.
– bpeikes
7 hours ago
|
show 1 more comment
I find myself often with code that looks like this:
bool isFirst = true;
for(const auto &item: items)
{
if(!isFirst)
{
// do something
}
// Normal processing
isFirst = false;
}
Seems like there ought to be better way to express this as it's a common pattern in functions that act like "join".
c++
I find myself often with code that looks like this:
bool isFirst = true;
for(const auto &item: items)
{
if(!isFirst)
{
// do something
}
// Normal processing
isFirst = false;
}
Seems like there ought to be better way to express this as it's a common pattern in functions that act like "join".
c++
c++
edited 8 hours ago
bpeikes
asked 11 hours ago
bpeikesbpeikes
59251744
59251744
That's why I'm sad thatbool
s don't have--
anymore...
– Quentin
11 hours ago
Shouldn't it beelse { /* Normal processing */ }
? In this case you can look at this answer (it skips the last element, the idea is similar): stackoverflow.com/a/35372958/2956272
– dyukha
11 hours ago
2
When my code requires special first-element action (which frankly, I could likely count on one hand the number of times I've needed that in the last five years and still have fingers left over), I don't use ranged-for. I use an iterator, and if-test, and a nested while loop thereafter. The only place that causes headache is when the action taken is a precursor and not an alternative (i.e. the model you're using is such a case: first element gets actions A+B, remaining elements get B, as opposed to first element gets A, remaining get B).
– WhozCraig
11 hours ago
4
Possible duplicate of Skipping in Range-based for based on 'index'?
– hlscalon
11 hours ago
1
Thanks everyone. I think the a @Ali who posted on stackoverflow.com/questions/21215947/…, had great points. Moving the special case outside of the loop is a much better idea.
– bpeikes
7 hours ago
|
show 1 more comment
That's why I'm sad thatbool
s don't have--
anymore...
– Quentin
11 hours ago
Shouldn't it beelse { /* Normal processing */ }
? In this case you can look at this answer (it skips the last element, the idea is similar): stackoverflow.com/a/35372958/2956272
– dyukha
11 hours ago
2
When my code requires special first-element action (which frankly, I could likely count on one hand the number of times I've needed that in the last five years and still have fingers left over), I don't use ranged-for. I use an iterator, and if-test, and a nested while loop thereafter. The only place that causes headache is when the action taken is a precursor and not an alternative (i.e. the model you're using is such a case: first element gets actions A+B, remaining elements get B, as opposed to first element gets A, remaining get B).
– WhozCraig
11 hours ago
4
Possible duplicate of Skipping in Range-based for based on 'index'?
– hlscalon
11 hours ago
1
Thanks everyone. I think the a @Ali who posted on stackoverflow.com/questions/21215947/…, had great points. Moving the special case outside of the loop is a much better idea.
– bpeikes
7 hours ago
That's why I'm sad that
bool
s don't have --
anymore...– Quentin
11 hours ago
That's why I'm sad that
bool
s don't have --
anymore...– Quentin
11 hours ago
Shouldn't it be
else { /* Normal processing */ }
? In this case you can look at this answer (it skips the last element, the idea is similar): stackoverflow.com/a/35372958/2956272– dyukha
11 hours ago
Shouldn't it be
else { /* Normal processing */ }
? In this case you can look at this answer (it skips the last element, the idea is similar): stackoverflow.com/a/35372958/2956272– dyukha
11 hours ago
2
2
When my code requires special first-element action (which frankly, I could likely count on one hand the number of times I've needed that in the last five years and still have fingers left over), I don't use ranged-for. I use an iterator, and if-test, and a nested while loop thereafter. The only place that causes headache is when the action taken is a precursor and not an alternative (i.e. the model you're using is such a case: first element gets actions A+B, remaining elements get B, as opposed to first element gets A, remaining get B).
– WhozCraig
11 hours ago
When my code requires special first-element action (which frankly, I could likely count on one hand the number of times I've needed that in the last five years and still have fingers left over), I don't use ranged-for. I use an iterator, and if-test, and a nested while loop thereafter. The only place that causes headache is when the action taken is a precursor and not an alternative (i.e. the model you're using is such a case: first element gets actions A+B, remaining elements get B, as opposed to first element gets A, remaining get B).
– WhozCraig
11 hours ago
4
4
Possible duplicate of Skipping in Range-based for based on 'index'?
– hlscalon
11 hours ago
Possible duplicate of Skipping in Range-based for based on 'index'?
– hlscalon
11 hours ago
1
1
Thanks everyone. I think the a @Ali who posted on stackoverflow.com/questions/21215947/…, had great points. Moving the special case outside of the loop is a much better idea.
– bpeikes
7 hours ago
Thanks everyone. I think the a @Ali who posted on stackoverflow.com/questions/21215947/…, had great points. Moving the special case outside of the loop is a much better idea.
– bpeikes
7 hours ago
|
show 1 more comment
5 Answers
5
active
oldest
votes
You can't know which element you are visiting in a range based for loop unless you are looping over a container like an array
or vector
where you can take the address of the object and compare it to the address of the first item to figure out where in the container you are. You can also do this if the container provides lookup by value, you can see if the iterator returned from the find operation is the same as the begin
iterator.
If you need special handling for the first element then you can fall back to a traditional for loop like
for (auto it = std::begin(items), first = it, end = std::end(items); it != end; ++it)
{
if (it == first)
{
// do something
}
// Normal processing
}
If what you need to do can be factored out of the loop then you could use a range based for loop and just put the processing before the loop like
// do something
for(const auto &item: items)
{
// Normal processing
}
1
Your first example could be nicely wrapped into a (algorithm) template taking an iterator range and twostd::functions
(FirstElementProcessor,, OtherElementProcessor).
– πάντα ῥεῖ
11 hours ago
I've thought a template, but I was wondering if there was anything already like this, since it seems to be a common pattern.
– bpeikes
11 hours ago
add a comment |
A fun alternative solution, that I would not use in production without great care, would be to use custom iterator.
int main() {
std::vector<int> v{1,2,3,4};
for (const auto & [is_first,b] : wrap(v)) {
if (is_first) {
std::cout << "First: ";
}
std::cout << b << std::endl;
}
}
A toy implementation could look like this:
template<typename T>
struct collection_wrap {
collection_wrap(T &c): c_(c) {}
struct magic_iterator {
bool is_first = false;
typename T::iterator itr;
auto operator*() {
return std::make_tuple(is_first, *itr);
}
magic_iterator operator++() {
magic_iterator self = *this;
itr++;
//only works for forward
is_first = false;
return self;
}
bool operator!=(const magic_iterator &o) {
return itr != o.itr;
}
};
magic_iterator begin() {
magic_iterator itr;
itr.is_first = true;
itr.itr = c_.begin();
return itr;
}
magic_iterator end() {
magic_iterator itr;
itr.is_first = false;
itr.itr = c_.end();
return itr;
}
T &c_;
};
template<typename Collection>
collection_wrap<Collection>
wrap(Collection &vec) {
return collection_wrap(vec);
}
Is the square bracket a "structured binding"?
– Costantino Grana
10 hours ago
You should addtemplate<typename T> void warp(T&& t) = delete;
to prevent use of dangling references
– Yankes
9 hours ago
add a comment |
Maybe a for_first_then_each
is what you're looking for? It takes you range in terms of iterators and applies the first function to the first element and the second function to the rest.
#include <iostream>
#include <vector>
template<typename BeginIt, typename EndIt, typename FirstFun, typename OthersFun>
void for_first_then_each(BeginIt begin, EndIt end, FirstFun firstFun, OthersFun othersFun) {
if(begin == end) return;
firstFun(*begin);
for(auto it = std::next(begin); it != end; ++it) {
othersFun(*it);
};
}
int main() {
std::vector<int> v = {0, 1, 2, 3};
for_first_then_each(v.begin(), v.end(),
(auto first) { std::cout << first + 42 << 'n'; },
(auto other) { std::cout << other - 42 << 'n'; }
);
// Outputs 42, -41, -40, -39
return 0;
}
add a comment |
I think it can be a bit simplified.
for (const auto &item : items)
{
if (&item == &(*std::begin(items)))
{
// do something
}
// Normal processing
}
1
Not allitems
containers usable with a range based for loop necessarily implement an access tofront()
.
– πάντα ῥεῖ
11 hours ago
Also this looks somewhat brittle to me. If someone replacesconst auto &item
withauto
, it will silently break.
– HolyBlackCat
11 hours ago
@HolyBlackCat, I am considering an author question.
– Dmytro Dadyka
11 hours ago
1
This seems expensive, and introduces iterators, which is what you're trying to hide by using a range based loop.
– bpeikes
11 hours ago
if (&item == &(*items.begin()))
is also not going to work. ifitems
is a raw array there is nobegin
member function.
– NathanOliver
10 hours ago
|
show 3 more comments
I assume you want to know how to retrieve the first element, you could do this with an array
and a vector
.
I'm going to show the array
here.
First include this in your code:
#include <array>
Then convert your array accordingly:
std::array<std::string, 4> items={"test1", "test2", "test3", "test4"};
for(const auto &item: items)
{
if(item == items.front()){
// do something
printf("nFirst: %sn", item.c_str()); //or simply printf("nFirst:"); since you gonna output a double element
}
// Normal processing
printf("Item: %sn", item.c_str());
}
return 0;
}
2
Why are you usingprintf()
in c++ code? "Performance" cargo culting?
– πάντα ῥεῖ
10 hours ago
4
@πάνταῥεῖ: I useprintf
all the time in my C++ code. I'm allowed to, and I prefer it, and it works, so who are you to judge me?
– TonyK
10 hours ago
1
Not all items containers usable with a range based for loop necessarily implement an access to front()
– Dmytro Dadyka
10 hours ago
@πάνταῥεῖ Yeah, I like printf more, what can you do. Didn't know people downvoted for that. :D
– Secko
10 hours ago
I didn't downvote, and certainly not for that. I've just been asking, because it's unusual to see in clean c++ code. Also cargo cult programming is a well established term in modern software development.
– πάντα ῥεῖ
10 hours ago
|
show 5 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54831971%2fc-range-based-loop-with-special-case-for-first-item%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can't know which element you are visiting in a range based for loop unless you are looping over a container like an array
or vector
where you can take the address of the object and compare it to the address of the first item to figure out where in the container you are. You can also do this if the container provides lookup by value, you can see if the iterator returned from the find operation is the same as the begin
iterator.
If you need special handling for the first element then you can fall back to a traditional for loop like
for (auto it = std::begin(items), first = it, end = std::end(items); it != end; ++it)
{
if (it == first)
{
// do something
}
// Normal processing
}
If what you need to do can be factored out of the loop then you could use a range based for loop and just put the processing before the loop like
// do something
for(const auto &item: items)
{
// Normal processing
}
1
Your first example could be nicely wrapped into a (algorithm) template taking an iterator range and twostd::functions
(FirstElementProcessor,, OtherElementProcessor).
– πάντα ῥεῖ
11 hours ago
I've thought a template, but I was wondering if there was anything already like this, since it seems to be a common pattern.
– bpeikes
11 hours ago
add a comment |
You can't know which element you are visiting in a range based for loop unless you are looping over a container like an array
or vector
where you can take the address of the object and compare it to the address of the first item to figure out where in the container you are. You can also do this if the container provides lookup by value, you can see if the iterator returned from the find operation is the same as the begin
iterator.
If you need special handling for the first element then you can fall back to a traditional for loop like
for (auto it = std::begin(items), first = it, end = std::end(items); it != end; ++it)
{
if (it == first)
{
// do something
}
// Normal processing
}
If what you need to do can be factored out of the loop then you could use a range based for loop and just put the processing before the loop like
// do something
for(const auto &item: items)
{
// Normal processing
}
1
Your first example could be nicely wrapped into a (algorithm) template taking an iterator range and twostd::functions
(FirstElementProcessor,, OtherElementProcessor).
– πάντα ῥεῖ
11 hours ago
I've thought a template, but I was wondering if there was anything already like this, since it seems to be a common pattern.
– bpeikes
11 hours ago
add a comment |
You can't know which element you are visiting in a range based for loop unless you are looping over a container like an array
or vector
where you can take the address of the object and compare it to the address of the first item to figure out where in the container you are. You can also do this if the container provides lookup by value, you can see if the iterator returned from the find operation is the same as the begin
iterator.
If you need special handling for the first element then you can fall back to a traditional for loop like
for (auto it = std::begin(items), first = it, end = std::end(items); it != end; ++it)
{
if (it == first)
{
// do something
}
// Normal processing
}
If what you need to do can be factored out of the loop then you could use a range based for loop and just put the processing before the loop like
// do something
for(const auto &item: items)
{
// Normal processing
}
You can't know which element you are visiting in a range based for loop unless you are looping over a container like an array
or vector
where you can take the address of the object and compare it to the address of the first item to figure out where in the container you are. You can also do this if the container provides lookup by value, you can see if the iterator returned from the find operation is the same as the begin
iterator.
If you need special handling for the first element then you can fall back to a traditional for loop like
for (auto it = std::begin(items), first = it, end = std::end(items); it != end; ++it)
{
if (it == first)
{
// do something
}
// Normal processing
}
If what you need to do can be factored out of the loop then you could use a range based for loop and just put the processing before the loop like
// do something
for(const auto &item: items)
{
// Normal processing
}
edited 11 hours ago
scohe001
8,07512341
8,07512341
answered 11 hours ago
NathanOliverNathanOliver
93.2k16130196
93.2k16130196
1
Your first example could be nicely wrapped into a (algorithm) template taking an iterator range and twostd::functions
(FirstElementProcessor,, OtherElementProcessor).
– πάντα ῥεῖ
11 hours ago
I've thought a template, but I was wondering if there was anything already like this, since it seems to be a common pattern.
– bpeikes
11 hours ago
add a comment |
1
Your first example could be nicely wrapped into a (algorithm) template taking an iterator range and twostd::functions
(FirstElementProcessor,, OtherElementProcessor).
– πάντα ῥεῖ
11 hours ago
I've thought a template, but I was wondering if there was anything already like this, since it seems to be a common pattern.
– bpeikes
11 hours ago
1
1
Your first example could be nicely wrapped into a (algorithm) template taking an iterator range and two
std::functions
(FirstElementProcessor,, OtherElementProcessor).– πάντα ῥεῖ
11 hours ago
Your first example could be nicely wrapped into a (algorithm) template taking an iterator range and two
std::functions
(FirstElementProcessor,, OtherElementProcessor).– πάντα ῥεῖ
11 hours ago
I've thought a template, but I was wondering if there was anything already like this, since it seems to be a common pattern.
– bpeikes
11 hours ago
I've thought a template, but I was wondering if there was anything already like this, since it seems to be a common pattern.
– bpeikes
11 hours ago
add a comment |
A fun alternative solution, that I would not use in production without great care, would be to use custom iterator.
int main() {
std::vector<int> v{1,2,3,4};
for (const auto & [is_first,b] : wrap(v)) {
if (is_first) {
std::cout << "First: ";
}
std::cout << b << std::endl;
}
}
A toy implementation could look like this:
template<typename T>
struct collection_wrap {
collection_wrap(T &c): c_(c) {}
struct magic_iterator {
bool is_first = false;
typename T::iterator itr;
auto operator*() {
return std::make_tuple(is_first, *itr);
}
magic_iterator operator++() {
magic_iterator self = *this;
itr++;
//only works for forward
is_first = false;
return self;
}
bool operator!=(const magic_iterator &o) {
return itr != o.itr;
}
};
magic_iterator begin() {
magic_iterator itr;
itr.is_first = true;
itr.itr = c_.begin();
return itr;
}
magic_iterator end() {
magic_iterator itr;
itr.is_first = false;
itr.itr = c_.end();
return itr;
}
T &c_;
};
template<typename Collection>
collection_wrap<Collection>
wrap(Collection &vec) {
return collection_wrap(vec);
}
Is the square bracket a "structured binding"?
– Costantino Grana
10 hours ago
You should addtemplate<typename T> void warp(T&& t) = delete;
to prevent use of dangling references
– Yankes
9 hours ago
add a comment |
A fun alternative solution, that I would not use in production without great care, would be to use custom iterator.
int main() {
std::vector<int> v{1,2,3,4};
for (const auto & [is_first,b] : wrap(v)) {
if (is_first) {
std::cout << "First: ";
}
std::cout << b << std::endl;
}
}
A toy implementation could look like this:
template<typename T>
struct collection_wrap {
collection_wrap(T &c): c_(c) {}
struct magic_iterator {
bool is_first = false;
typename T::iterator itr;
auto operator*() {
return std::make_tuple(is_first, *itr);
}
magic_iterator operator++() {
magic_iterator self = *this;
itr++;
//only works for forward
is_first = false;
return self;
}
bool operator!=(const magic_iterator &o) {
return itr != o.itr;
}
};
magic_iterator begin() {
magic_iterator itr;
itr.is_first = true;
itr.itr = c_.begin();
return itr;
}
magic_iterator end() {
magic_iterator itr;
itr.is_first = false;
itr.itr = c_.end();
return itr;
}
T &c_;
};
template<typename Collection>
collection_wrap<Collection>
wrap(Collection &vec) {
return collection_wrap(vec);
}
Is the square bracket a "structured binding"?
– Costantino Grana
10 hours ago
You should addtemplate<typename T> void warp(T&& t) = delete;
to prevent use of dangling references
– Yankes
9 hours ago
add a comment |
A fun alternative solution, that I would not use in production without great care, would be to use custom iterator.
int main() {
std::vector<int> v{1,2,3,4};
for (const auto & [is_first,b] : wrap(v)) {
if (is_first) {
std::cout << "First: ";
}
std::cout << b << std::endl;
}
}
A toy implementation could look like this:
template<typename T>
struct collection_wrap {
collection_wrap(T &c): c_(c) {}
struct magic_iterator {
bool is_first = false;
typename T::iterator itr;
auto operator*() {
return std::make_tuple(is_first, *itr);
}
magic_iterator operator++() {
magic_iterator self = *this;
itr++;
//only works for forward
is_first = false;
return self;
}
bool operator!=(const magic_iterator &o) {
return itr != o.itr;
}
};
magic_iterator begin() {
magic_iterator itr;
itr.is_first = true;
itr.itr = c_.begin();
return itr;
}
magic_iterator end() {
magic_iterator itr;
itr.is_first = false;
itr.itr = c_.end();
return itr;
}
T &c_;
};
template<typename Collection>
collection_wrap<Collection>
wrap(Collection &vec) {
return collection_wrap(vec);
}
A fun alternative solution, that I would not use in production without great care, would be to use custom iterator.
int main() {
std::vector<int> v{1,2,3,4};
for (const auto & [is_first,b] : wrap(v)) {
if (is_first) {
std::cout << "First: ";
}
std::cout << b << std::endl;
}
}
A toy implementation could look like this:
template<typename T>
struct collection_wrap {
collection_wrap(T &c): c_(c) {}
struct magic_iterator {
bool is_first = false;
typename T::iterator itr;
auto operator*() {
return std::make_tuple(is_first, *itr);
}
magic_iterator operator++() {
magic_iterator self = *this;
itr++;
//only works for forward
is_first = false;
return self;
}
bool operator!=(const magic_iterator &o) {
return itr != o.itr;
}
};
magic_iterator begin() {
magic_iterator itr;
itr.is_first = true;
itr.itr = c_.begin();
return itr;
}
magic_iterator end() {
magic_iterator itr;
itr.is_first = false;
itr.itr = c_.end();
return itr;
}
T &c_;
};
template<typename Collection>
collection_wrap<Collection>
wrap(Collection &vec) {
return collection_wrap(vec);
}
answered 11 hours ago
XaqqXaqq
3,67821737
3,67821737
Is the square bracket a "structured binding"?
– Costantino Grana
10 hours ago
You should addtemplate<typename T> void warp(T&& t) = delete;
to prevent use of dangling references
– Yankes
9 hours ago
add a comment |
Is the square bracket a "structured binding"?
– Costantino Grana
10 hours ago
You should addtemplate<typename T> void warp(T&& t) = delete;
to prevent use of dangling references
– Yankes
9 hours ago
Is the square bracket a "structured binding"?
– Costantino Grana
10 hours ago
Is the square bracket a "structured binding"?
– Costantino Grana
10 hours ago
You should add
template<typename T> void warp(T&& t) = delete;
to prevent use of dangling references– Yankes
9 hours ago
You should add
template<typename T> void warp(T&& t) = delete;
to prevent use of dangling references– Yankes
9 hours ago
add a comment |
Maybe a for_first_then_each
is what you're looking for? It takes you range in terms of iterators and applies the first function to the first element and the second function to the rest.
#include <iostream>
#include <vector>
template<typename BeginIt, typename EndIt, typename FirstFun, typename OthersFun>
void for_first_then_each(BeginIt begin, EndIt end, FirstFun firstFun, OthersFun othersFun) {
if(begin == end) return;
firstFun(*begin);
for(auto it = std::next(begin); it != end; ++it) {
othersFun(*it);
};
}
int main() {
std::vector<int> v = {0, 1, 2, 3};
for_first_then_each(v.begin(), v.end(),
(auto first) { std::cout << first + 42 << 'n'; },
(auto other) { std::cout << other - 42 << 'n'; }
);
// Outputs 42, -41, -40, -39
return 0;
}
add a comment |
Maybe a for_first_then_each
is what you're looking for? It takes you range in terms of iterators and applies the first function to the first element and the second function to the rest.
#include <iostream>
#include <vector>
template<typename BeginIt, typename EndIt, typename FirstFun, typename OthersFun>
void for_first_then_each(BeginIt begin, EndIt end, FirstFun firstFun, OthersFun othersFun) {
if(begin == end) return;
firstFun(*begin);
for(auto it = std::next(begin); it != end; ++it) {
othersFun(*it);
};
}
int main() {
std::vector<int> v = {0, 1, 2, 3};
for_first_then_each(v.begin(), v.end(),
(auto first) { std::cout << first + 42 << 'n'; },
(auto other) { std::cout << other - 42 << 'n'; }
);
// Outputs 42, -41, -40, -39
return 0;
}
add a comment |
Maybe a for_first_then_each
is what you're looking for? It takes you range in terms of iterators and applies the first function to the first element and the second function to the rest.
#include <iostream>
#include <vector>
template<typename BeginIt, typename EndIt, typename FirstFun, typename OthersFun>
void for_first_then_each(BeginIt begin, EndIt end, FirstFun firstFun, OthersFun othersFun) {
if(begin == end) return;
firstFun(*begin);
for(auto it = std::next(begin); it != end; ++it) {
othersFun(*it);
};
}
int main() {
std::vector<int> v = {0, 1, 2, 3};
for_first_then_each(v.begin(), v.end(),
(auto first) { std::cout << first + 42 << 'n'; },
(auto other) { std::cout << other - 42 << 'n'; }
);
// Outputs 42, -41, -40, -39
return 0;
}
Maybe a for_first_then_each
is what you're looking for? It takes you range in terms of iterators and applies the first function to the first element and the second function to the rest.
#include <iostream>
#include <vector>
template<typename BeginIt, typename EndIt, typename FirstFun, typename OthersFun>
void for_first_then_each(BeginIt begin, EndIt end, FirstFun firstFun, OthersFun othersFun) {
if(begin == end) return;
firstFun(*begin);
for(auto it = std::next(begin); it != end; ++it) {
othersFun(*it);
};
}
int main() {
std::vector<int> v = {0, 1, 2, 3};
for_first_then_each(v.begin(), v.end(),
(auto first) { std::cout << first + 42 << 'n'; },
(auto other) { std::cout << other - 42 << 'n'; }
);
// Outputs 42, -41, -40, -39
return 0;
}
answered 9 hours ago
Joakim ThorénJoakim Thorén
6428
6428
add a comment |
add a comment |
I think it can be a bit simplified.
for (const auto &item : items)
{
if (&item == &(*std::begin(items)))
{
// do something
}
// Normal processing
}
1
Not allitems
containers usable with a range based for loop necessarily implement an access tofront()
.
– πάντα ῥεῖ
11 hours ago
Also this looks somewhat brittle to me. If someone replacesconst auto &item
withauto
, it will silently break.
– HolyBlackCat
11 hours ago
@HolyBlackCat, I am considering an author question.
– Dmytro Dadyka
11 hours ago
1
This seems expensive, and introduces iterators, which is what you're trying to hide by using a range based loop.
– bpeikes
11 hours ago
if (&item == &(*items.begin()))
is also not going to work. ifitems
is a raw array there is nobegin
member function.
– NathanOliver
10 hours ago
|
show 3 more comments
I think it can be a bit simplified.
for (const auto &item : items)
{
if (&item == &(*std::begin(items)))
{
// do something
}
// Normal processing
}
1
Not allitems
containers usable with a range based for loop necessarily implement an access tofront()
.
– πάντα ῥεῖ
11 hours ago
Also this looks somewhat brittle to me. If someone replacesconst auto &item
withauto
, it will silently break.
– HolyBlackCat
11 hours ago
@HolyBlackCat, I am considering an author question.
– Dmytro Dadyka
11 hours ago
1
This seems expensive, and introduces iterators, which is what you're trying to hide by using a range based loop.
– bpeikes
11 hours ago
if (&item == &(*items.begin()))
is also not going to work. ifitems
is a raw array there is nobegin
member function.
– NathanOliver
10 hours ago
|
show 3 more comments
I think it can be a bit simplified.
for (const auto &item : items)
{
if (&item == &(*std::begin(items)))
{
// do something
}
// Normal processing
}
I think it can be a bit simplified.
for (const auto &item : items)
{
if (&item == &(*std::begin(items)))
{
// do something
}
// Normal processing
}
edited 10 hours ago
answered 11 hours ago
Dmytro DadykaDmytro Dadyka
8121618
8121618
1
Not allitems
containers usable with a range based for loop necessarily implement an access tofront()
.
– πάντα ῥεῖ
11 hours ago
Also this looks somewhat brittle to me. If someone replacesconst auto &item
withauto
, it will silently break.
– HolyBlackCat
11 hours ago
@HolyBlackCat, I am considering an author question.
– Dmytro Dadyka
11 hours ago
1
This seems expensive, and introduces iterators, which is what you're trying to hide by using a range based loop.
– bpeikes
11 hours ago
if (&item == &(*items.begin()))
is also not going to work. ifitems
is a raw array there is nobegin
member function.
– NathanOliver
10 hours ago
|
show 3 more comments
1
Not allitems
containers usable with a range based for loop necessarily implement an access tofront()
.
– πάντα ῥεῖ
11 hours ago
Also this looks somewhat brittle to me. If someone replacesconst auto &item
withauto
, it will silently break.
– HolyBlackCat
11 hours ago
@HolyBlackCat, I am considering an author question.
– Dmytro Dadyka
11 hours ago
1
This seems expensive, and introduces iterators, which is what you're trying to hide by using a range based loop.
– bpeikes
11 hours ago
if (&item == &(*items.begin()))
is also not going to work. ifitems
is a raw array there is nobegin
member function.
– NathanOliver
10 hours ago
1
1
Not all
items
containers usable with a range based for loop necessarily implement an access to front()
.– πάντα ῥεῖ
11 hours ago
Not all
items
containers usable with a range based for loop necessarily implement an access to front()
.– πάντα ῥεῖ
11 hours ago
Also this looks somewhat brittle to me. If someone replaces
const auto &item
with auto
, it will silently break.– HolyBlackCat
11 hours ago
Also this looks somewhat brittle to me. If someone replaces
const auto &item
with auto
, it will silently break.– HolyBlackCat
11 hours ago
@HolyBlackCat, I am considering an author question.
– Dmytro Dadyka
11 hours ago
@HolyBlackCat, I am considering an author question.
– Dmytro Dadyka
11 hours ago
1
1
This seems expensive, and introduces iterators, which is what you're trying to hide by using a range based loop.
– bpeikes
11 hours ago
This seems expensive, and introduces iterators, which is what you're trying to hide by using a range based loop.
– bpeikes
11 hours ago
if (&item == &(*items.begin()))
is also not going to work. if items
is a raw array there is no begin
member function.– NathanOliver
10 hours ago
if (&item == &(*items.begin()))
is also not going to work. if items
is a raw array there is no begin
member function.– NathanOliver
10 hours ago
|
show 3 more comments
I assume you want to know how to retrieve the first element, you could do this with an array
and a vector
.
I'm going to show the array
here.
First include this in your code:
#include <array>
Then convert your array accordingly:
std::array<std::string, 4> items={"test1", "test2", "test3", "test4"};
for(const auto &item: items)
{
if(item == items.front()){
// do something
printf("nFirst: %sn", item.c_str()); //or simply printf("nFirst:"); since you gonna output a double element
}
// Normal processing
printf("Item: %sn", item.c_str());
}
return 0;
}
2
Why are you usingprintf()
in c++ code? "Performance" cargo culting?
– πάντα ῥεῖ
10 hours ago
4
@πάνταῥεῖ: I useprintf
all the time in my C++ code. I'm allowed to, and I prefer it, and it works, so who are you to judge me?
– TonyK
10 hours ago
1
Not all items containers usable with a range based for loop necessarily implement an access to front()
– Dmytro Dadyka
10 hours ago
@πάνταῥεῖ Yeah, I like printf more, what can you do. Didn't know people downvoted for that. :D
– Secko
10 hours ago
I didn't downvote, and certainly not for that. I've just been asking, because it's unusual to see in clean c++ code. Also cargo cult programming is a well established term in modern software development.
– πάντα ῥεῖ
10 hours ago
|
show 5 more comments
I assume you want to know how to retrieve the first element, you could do this with an array
and a vector
.
I'm going to show the array
here.
First include this in your code:
#include <array>
Then convert your array accordingly:
std::array<std::string, 4> items={"test1", "test2", "test3", "test4"};
for(const auto &item: items)
{
if(item == items.front()){
// do something
printf("nFirst: %sn", item.c_str()); //or simply printf("nFirst:"); since you gonna output a double element
}
// Normal processing
printf("Item: %sn", item.c_str());
}
return 0;
}
2
Why are you usingprintf()
in c++ code? "Performance" cargo culting?
– πάντα ῥεῖ
10 hours ago
4
@πάνταῥεῖ: I useprintf
all the time in my C++ code. I'm allowed to, and I prefer it, and it works, so who are you to judge me?
– TonyK
10 hours ago
1
Not all items containers usable with a range based for loop necessarily implement an access to front()
– Dmytro Dadyka
10 hours ago
@πάνταῥεῖ Yeah, I like printf more, what can you do. Didn't know people downvoted for that. :D
– Secko
10 hours ago
I didn't downvote, and certainly not for that. I've just been asking, because it's unusual to see in clean c++ code. Also cargo cult programming is a well established term in modern software development.
– πάντα ῥεῖ
10 hours ago
|
show 5 more comments
I assume you want to know how to retrieve the first element, you could do this with an array
and a vector
.
I'm going to show the array
here.
First include this in your code:
#include <array>
Then convert your array accordingly:
std::array<std::string, 4> items={"test1", "test2", "test3", "test4"};
for(const auto &item: items)
{
if(item == items.front()){
// do something
printf("nFirst: %sn", item.c_str()); //or simply printf("nFirst:"); since you gonna output a double element
}
// Normal processing
printf("Item: %sn", item.c_str());
}
return 0;
}
I assume you want to know how to retrieve the first element, you could do this with an array
and a vector
.
I'm going to show the array
here.
First include this in your code:
#include <array>
Then convert your array accordingly:
std::array<std::string, 4> items={"test1", "test2", "test3", "test4"};
for(const auto &item: items)
{
if(item == items.front()){
// do something
printf("nFirst: %sn", item.c_str()); //or simply printf("nFirst:"); since you gonna output a double element
}
// Normal processing
printf("Item: %sn", item.c_str());
}
return 0;
}
edited 9 hours ago
answered 10 hours ago
SeckoSecko
5,47532433
5,47532433
2
Why are you usingprintf()
in c++ code? "Performance" cargo culting?
– πάντα ῥεῖ
10 hours ago
4
@πάνταῥεῖ: I useprintf
all the time in my C++ code. I'm allowed to, and I prefer it, and it works, so who are you to judge me?
– TonyK
10 hours ago
1
Not all items containers usable with a range based for loop necessarily implement an access to front()
– Dmytro Dadyka
10 hours ago
@πάνταῥεῖ Yeah, I like printf more, what can you do. Didn't know people downvoted for that. :D
– Secko
10 hours ago
I didn't downvote, and certainly not for that. I've just been asking, because it's unusual to see in clean c++ code. Also cargo cult programming is a well established term in modern software development.
– πάντα ῥεῖ
10 hours ago
|
show 5 more comments
2
Why are you usingprintf()
in c++ code? "Performance" cargo culting?
– πάντα ῥεῖ
10 hours ago
4
@πάνταῥεῖ: I useprintf
all the time in my C++ code. I'm allowed to, and I prefer it, and it works, so who are you to judge me?
– TonyK
10 hours ago
1
Not all items containers usable with a range based for loop necessarily implement an access to front()
– Dmytro Dadyka
10 hours ago
@πάνταῥεῖ Yeah, I like printf more, what can you do. Didn't know people downvoted for that. :D
– Secko
10 hours ago
I didn't downvote, and certainly not for that. I've just been asking, because it's unusual to see in clean c++ code. Also cargo cult programming is a well established term in modern software development.
– πάντα ῥεῖ
10 hours ago
2
2
Why are you using
printf()
in c++ code? "Performance" cargo culting?– πάντα ῥεῖ
10 hours ago
Why are you using
printf()
in c++ code? "Performance" cargo culting?– πάντα ῥεῖ
10 hours ago
4
4
@πάνταῥεῖ: I use
printf
all the time in my C++ code. I'm allowed to, and I prefer it, and it works, so who are you to judge me?– TonyK
10 hours ago
@πάνταῥεῖ: I use
printf
all the time in my C++ code. I'm allowed to, and I prefer it, and it works, so who are you to judge me?– TonyK
10 hours ago
1
1
Not all items containers usable with a range based for loop necessarily implement an access to front()
– Dmytro Dadyka
10 hours ago
Not all items containers usable with a range based for loop necessarily implement an access to front()
– Dmytro Dadyka
10 hours ago
@πάνταῥεῖ Yeah, I like printf more, what can you do. Didn't know people downvoted for that. :D
– Secko
10 hours ago
@πάνταῥεῖ Yeah, I like printf more, what can you do. Didn't know people downvoted for that. :D
– Secko
10 hours ago
I didn't downvote, and certainly not for that. I've just been asking, because it's unusual to see in clean c++ code. Also cargo cult programming is a well established term in modern software development.
– πάντα ῥεῖ
10 hours ago
I didn't downvote, and certainly not for that. I've just been asking, because it's unusual to see in clean c++ code. Also cargo cult programming is a well established term in modern software development.
– πάντα ῥεῖ
10 hours ago
|
show 5 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54831971%2fc-range-based-loop-with-special-case-for-first-item%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
That's why I'm sad that
bool
s don't have--
anymore...– Quentin
11 hours ago
Shouldn't it be
else { /* Normal processing */ }
? In this case you can look at this answer (it skips the last element, the idea is similar): stackoverflow.com/a/35372958/2956272– dyukha
11 hours ago
2
When my code requires special first-element action (which frankly, I could likely count on one hand the number of times I've needed that in the last five years and still have fingers left over), I don't use ranged-for. I use an iterator, and if-test, and a nested while loop thereafter. The only place that causes headache is when the action taken is a precursor and not an alternative (i.e. the model you're using is such a case: first element gets actions A+B, remaining elements get B, as opposed to first element gets A, remaining get B).
– WhozCraig
11 hours ago
4
Possible duplicate of Skipping in Range-based for based on 'index'?
– hlscalon
11 hours ago
1
Thanks everyone. I think the a @Ali who posted on stackoverflow.com/questions/21215947/…, had great points. Moving the special case outside of the loop is a much better idea.
– bpeikes
7 hours ago