Passing functions in C++
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
Suppose I want to write a function that calls a nullary function 100 times. Which of these implementations is best and why?
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(const F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
Or is there a better implementation?
Update regarding 4
struct S {
S() {}
S(const S&) = delete;
void operator()() const {}
};
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
int main() {
const S s;
call100(s);
}
c++ c++17
add a comment |
Suppose I want to write a function that calls a nullary function 100 times. Which of these implementations is best and why?
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(const F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
Or is there a better implementation?
Update regarding 4
struct S {
S() {}
S(const S&) = delete;
void operator()() const {}
};
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
int main() {
const S s;
call100(s);
}
c++ c++17
1
go for the last one.
– Hoodi
yesterday
6
@Hoodi: Why?...
– Andrew Tomazos
yesterday
Because in your sample code, you just call f one hundred times and you have not changed F. So, go for the last one.
– Hoodi
yesterday
8
@Hoodi - You have no way to know iffhas any state that changes by callingf(). That template accepts general functors.
– StoryTeller
yesterday
add a comment |
Suppose I want to write a function that calls a nullary function 100 times. Which of these implementations is best and why?
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(const F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
Or is there a better implementation?
Update regarding 4
struct S {
S() {}
S(const S&) = delete;
void operator()() const {}
};
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
int main() {
const S s;
call100(s);
}
c++ c++17
Suppose I want to write a function that calls a nullary function 100 times. Which of these implementations is best and why?
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(const F& f) {
for (int i = 0; i < 100; i++)
f();
}
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
Or is there a better implementation?
Update regarding 4
struct S {
S() {}
S(const S&) = delete;
void operator()() const {}
};
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; i++)
f();
}
int main() {
const S s;
call100(s);
}
c++ c++17
c++ c++17
edited yesterday
Andrew Tomazos
asked yesterday
Andrew TomazosAndrew Tomazos
35.9k26134236
35.9k26134236
1
go for the last one.
– Hoodi
yesterday
6
@Hoodi: Why?...
– Andrew Tomazos
yesterday
Because in your sample code, you just call f one hundred times and you have not changed F. So, go for the last one.
– Hoodi
yesterday
8
@Hoodi - You have no way to know iffhas any state that changes by callingf(). That template accepts general functors.
– StoryTeller
yesterday
add a comment |
1
go for the last one.
– Hoodi
yesterday
6
@Hoodi: Why?...
– Andrew Tomazos
yesterday
Because in your sample code, you just call f one hundred times and you have not changed F. So, go for the last one.
– Hoodi
yesterday
8
@Hoodi - You have no way to know iffhas any state that changes by callingf(). That template accepts general functors.
– StoryTeller
yesterday
1
1
go for the last one.
– Hoodi
yesterday
go for the last one.
– Hoodi
yesterday
6
6
@Hoodi: Why?...
– Andrew Tomazos
yesterday
@Hoodi: Why?...
– Andrew Tomazos
yesterday
Because in your sample code, you just call f one hundred times and you have not changed F. So, go for the last one.
– Hoodi
yesterday
Because in your sample code, you just call f one hundred times and you have not changed F. So, go for the last one.
– Hoodi
yesterday
8
8
@Hoodi - You have no way to know if
f has any state that changes by calling f(). That template accepts general functors.– StoryTeller
yesterday
@Hoodi - You have no way to know if
f has any state that changes by calling f(). That template accepts general functors.– StoryTeller
yesterday
add a comment |
3 Answers
3
active
oldest
votes
I would use the first one (pass the callable by value).
If a caller is concerned about the cost of copying the callable, then they can use std::ref(f) or std::cref(f) to pass it using reference_wrapper.
By doing this, you provide the most flexibility to the caller.
But in the main code of the question, it JUST calls the f 100 times. No?
– Hoodi
yesterday
5
Also note this is how the standard library does it in the algorithmns library (e.g.std::for_each,std::count_if)
– Artyer
yesterday
5
@Artyer Although those predate forwarding references.
– Barry
yesterday
add a comment |
The only runtime cost of
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; ++i)
f();
}
is that it can have more versions (copies of code) if you pass f in multiple ways. With MSVC or the gold linker with ICF, those copies only cost compile time unless they differ, and if they differ you probably want to keep them.
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; ++i)
f();
}
this one has the advantage of being value semantics; and following the rule of taking values unless you have good reason not to is reasonable. std::ref/std::cref let you call it with a persistant reference, and for prvalues c++17 guaranteed elision will prevent a spurious copy.
As a joke you could do:
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 99; ++i)
f();
std::forward<F>(f)();
}
but that relies on people having && overloads on their operator(), which nobody does.
add a comment |
I do not think there is a definitive answer:
The first one copies everything you pass in which might be expensive
for capturing lambdas but otherwise provides the most flexibility:
Pros
- Const objects allowed
- Mutable objects allowed (copied)
- Copy can be elided (?)
Cons
- Copies everything you give it
- You cannot call it with an existing object such as mutable lambda without copying it in
The second one cannot be used for const objects. On the other hand
it does not copy anything and allows mutable objects:
Pros
- Mutable objects allowed
- Copies nothing
Cons
- Does not allow const objects
The third one cannot be used for mutable lambdas so is a slight
modification of the second one.
Pros
- Const objects allowed
- Copies nothing
Cons
- Cannot be called with mutable objects
The fourth one cannot be called with const objects unless you copy
them which becomes quite awkward with lambdas. You also cannot use
it with pre-existing mutable lambda object without copying it or
moving from it (losing it in the process) which is similar
limitation to 1.
Pros
- Avoids copies explicitely by forcing (requiring) move semanthics if the copy is needed
- Mutable objects allowed.
- Const objects allowed (except for mutable lambdas)
Cons
- Does not allow const mutable lambdas without a copy
- You cannot call it with an existing object such as mutable lambda
And there you have it. There is no silver bullet here and there are different pros & cons to each of these versions. I tend to lean towards the first one being the default but with certain types of capturing lambdas or bigger callables, it might become an issue. And you cannot call the 1) with the mutable object and get an expected result. As mentioned in the other answer some of these can be overcome with std::ref and other ways of manipulating the actual T type. In my experience, these tend to be the source of pretty nasty bugs though when T is then something different than one expects to achieve i.e. mutability of a copy or such.
1
I don't think your analysis of 4 is correct. Passed a const value won't F be deduced as const T& and be passed by reference?
– Andrew Tomazos
yesterday
See "Update regarding 4"
– Andrew Tomazos
yesterday
@AndrewTomazos Not with const mutable lambdas. Or rather it will deduce it as you say but would refuse to compile because it would discard theconstat the call site. Using latest MSVC2017, not sure about Clang/GCC as Godbolt seems not to work atm.
– Resurrection
yesterday
1
@artyr No, that is nonsense. Feel free to test it yourself, but 4 won't calloperator()&&.
– Yakk - Adam Nevraumont
yesterday
add a comment |
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%2f55674830%2fpassing-functions-in-c%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
I would use the first one (pass the callable by value).
If a caller is concerned about the cost of copying the callable, then they can use std::ref(f) or std::cref(f) to pass it using reference_wrapper.
By doing this, you provide the most flexibility to the caller.
But in the main code of the question, it JUST calls the f 100 times. No?
– Hoodi
yesterday
5
Also note this is how the standard library does it in the algorithmns library (e.g.std::for_each,std::count_if)
– Artyer
yesterday
5
@Artyer Although those predate forwarding references.
– Barry
yesterday
add a comment |
I would use the first one (pass the callable by value).
If a caller is concerned about the cost of copying the callable, then they can use std::ref(f) or std::cref(f) to pass it using reference_wrapper.
By doing this, you provide the most flexibility to the caller.
But in the main code of the question, it JUST calls the f 100 times. No?
– Hoodi
yesterday
5
Also note this is how the standard library does it in the algorithmns library (e.g.std::for_each,std::count_if)
– Artyer
yesterday
5
@Artyer Although those predate forwarding references.
– Barry
yesterday
add a comment |
I would use the first one (pass the callable by value).
If a caller is concerned about the cost of copying the callable, then they can use std::ref(f) or std::cref(f) to pass it using reference_wrapper.
By doing this, you provide the most flexibility to the caller.
I would use the first one (pass the callable by value).
If a caller is concerned about the cost of copying the callable, then they can use std::ref(f) or std::cref(f) to pass it using reference_wrapper.
By doing this, you provide the most flexibility to the caller.
edited 20 hours ago
jww
54.4k42238518
54.4k42238518
answered yesterday
Marshall ClowMarshall Clow
7,6931635
7,6931635
But in the main code of the question, it JUST calls the f 100 times. No?
– Hoodi
yesterday
5
Also note this is how the standard library does it in the algorithmns library (e.g.std::for_each,std::count_if)
– Artyer
yesterday
5
@Artyer Although those predate forwarding references.
– Barry
yesterday
add a comment |
But in the main code of the question, it JUST calls the f 100 times. No?
– Hoodi
yesterday
5
Also note this is how the standard library does it in the algorithmns library (e.g.std::for_each,std::count_if)
– Artyer
yesterday
5
@Artyer Although those predate forwarding references.
– Barry
yesterday
But in the main code of the question, it JUST calls the f 100 times. No?
– Hoodi
yesterday
But in the main code of the question, it JUST calls the f 100 times. No?
– Hoodi
yesterday
5
5
Also note this is how the standard library does it in the algorithmns library (e.g.
std::for_each, std::count_if)– Artyer
yesterday
Also note this is how the standard library does it in the algorithmns library (e.g.
std::for_each, std::count_if)– Artyer
yesterday
5
5
@Artyer Although those predate forwarding references.
– Barry
yesterday
@Artyer Although those predate forwarding references.
– Barry
yesterday
add a comment |
The only runtime cost of
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; ++i)
f();
}
is that it can have more versions (copies of code) if you pass f in multiple ways. With MSVC or the gold linker with ICF, those copies only cost compile time unless they differ, and if they differ you probably want to keep them.
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; ++i)
f();
}
this one has the advantage of being value semantics; and following the rule of taking values unless you have good reason not to is reasonable. std::ref/std::cref let you call it with a persistant reference, and for prvalues c++17 guaranteed elision will prevent a spurious copy.
As a joke you could do:
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 99; ++i)
f();
std::forward<F>(f)();
}
but that relies on people having && overloads on their operator(), which nobody does.
add a comment |
The only runtime cost of
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; ++i)
f();
}
is that it can have more versions (copies of code) if you pass f in multiple ways. With MSVC or the gold linker with ICF, those copies only cost compile time unless they differ, and if they differ you probably want to keep them.
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; ++i)
f();
}
this one has the advantage of being value semantics; and following the rule of taking values unless you have good reason not to is reasonable. std::ref/std::cref let you call it with a persistant reference, and for prvalues c++17 guaranteed elision will prevent a spurious copy.
As a joke you could do:
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 99; ++i)
f();
std::forward<F>(f)();
}
but that relies on people having && overloads on their operator(), which nobody does.
add a comment |
The only runtime cost of
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; ++i)
f();
}
is that it can have more versions (copies of code) if you pass f in multiple ways. With MSVC or the gold linker with ICF, those copies only cost compile time unless they differ, and if they differ you probably want to keep them.
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; ++i)
f();
}
this one has the advantage of being value semantics; and following the rule of taking values unless you have good reason not to is reasonable. std::ref/std::cref let you call it with a persistant reference, and for prvalues c++17 guaranteed elision will prevent a spurious copy.
As a joke you could do:
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 99; ++i)
f();
std::forward<F>(f)();
}
but that relies on people having && overloads on their operator(), which nobody does.
The only runtime cost of
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 100; ++i)
f();
}
is that it can have more versions (copies of code) if you pass f in multiple ways. With MSVC or the gold linker with ICF, those copies only cost compile time unless they differ, and if they differ you probably want to keep them.
template<typename F>
void call100(F f) {
for (int i = 0; i < 100; ++i)
f();
}
this one has the advantage of being value semantics; and following the rule of taking values unless you have good reason not to is reasonable. std::ref/std::cref let you call it with a persistant reference, and for prvalues c++17 guaranteed elision will prevent a spurious copy.
As a joke you could do:
template<typename F>
void call100(F&& f) {
for (int i = 0; i < 99; ++i)
f();
std::forward<F>(f)();
}
but that relies on people having && overloads on their operator(), which nobody does.
edited yesterday
answered yesterday
Yakk - Adam NevraumontYakk - Adam Nevraumont
189k21200385
189k21200385
add a comment |
add a comment |
I do not think there is a definitive answer:
The first one copies everything you pass in which might be expensive
for capturing lambdas but otherwise provides the most flexibility:
Pros
- Const objects allowed
- Mutable objects allowed (copied)
- Copy can be elided (?)
Cons
- Copies everything you give it
- You cannot call it with an existing object such as mutable lambda without copying it in
The second one cannot be used for const objects. On the other hand
it does not copy anything and allows mutable objects:
Pros
- Mutable objects allowed
- Copies nothing
Cons
- Does not allow const objects
The third one cannot be used for mutable lambdas so is a slight
modification of the second one.
Pros
- Const objects allowed
- Copies nothing
Cons
- Cannot be called with mutable objects
The fourth one cannot be called with const objects unless you copy
them which becomes quite awkward with lambdas. You also cannot use
it with pre-existing mutable lambda object without copying it or
moving from it (losing it in the process) which is similar
limitation to 1.
Pros
- Avoids copies explicitely by forcing (requiring) move semanthics if the copy is needed
- Mutable objects allowed.
- Const objects allowed (except for mutable lambdas)
Cons
- Does not allow const mutable lambdas without a copy
- You cannot call it with an existing object such as mutable lambda
And there you have it. There is no silver bullet here and there are different pros & cons to each of these versions. I tend to lean towards the first one being the default but with certain types of capturing lambdas or bigger callables, it might become an issue. And you cannot call the 1) with the mutable object and get an expected result. As mentioned in the other answer some of these can be overcome with std::ref and other ways of manipulating the actual T type. In my experience, these tend to be the source of pretty nasty bugs though when T is then something different than one expects to achieve i.e. mutability of a copy or such.
1
I don't think your analysis of 4 is correct. Passed a const value won't F be deduced as const T& and be passed by reference?
– Andrew Tomazos
yesterday
See "Update regarding 4"
– Andrew Tomazos
yesterday
@AndrewTomazos Not with const mutable lambdas. Or rather it will deduce it as you say but would refuse to compile because it would discard theconstat the call site. Using latest MSVC2017, not sure about Clang/GCC as Godbolt seems not to work atm.
– Resurrection
yesterday
1
@artyr No, that is nonsense. Feel free to test it yourself, but 4 won't calloperator()&&.
– Yakk - Adam Nevraumont
yesterday
add a comment |
I do not think there is a definitive answer:
The first one copies everything you pass in which might be expensive
for capturing lambdas but otherwise provides the most flexibility:
Pros
- Const objects allowed
- Mutable objects allowed (copied)
- Copy can be elided (?)
Cons
- Copies everything you give it
- You cannot call it with an existing object such as mutable lambda without copying it in
The second one cannot be used for const objects. On the other hand
it does not copy anything and allows mutable objects:
Pros
- Mutable objects allowed
- Copies nothing
Cons
- Does not allow const objects
The third one cannot be used for mutable lambdas so is a slight
modification of the second one.
Pros
- Const objects allowed
- Copies nothing
Cons
- Cannot be called with mutable objects
The fourth one cannot be called with const objects unless you copy
them which becomes quite awkward with lambdas. You also cannot use
it with pre-existing mutable lambda object without copying it or
moving from it (losing it in the process) which is similar
limitation to 1.
Pros
- Avoids copies explicitely by forcing (requiring) move semanthics if the copy is needed
- Mutable objects allowed.
- Const objects allowed (except for mutable lambdas)
Cons
- Does not allow const mutable lambdas without a copy
- You cannot call it with an existing object such as mutable lambda
And there you have it. There is no silver bullet here and there are different pros & cons to each of these versions. I tend to lean towards the first one being the default but with certain types of capturing lambdas or bigger callables, it might become an issue. And you cannot call the 1) with the mutable object and get an expected result. As mentioned in the other answer some of these can be overcome with std::ref and other ways of manipulating the actual T type. In my experience, these tend to be the source of pretty nasty bugs though when T is then something different than one expects to achieve i.e. mutability of a copy or such.
1
I don't think your analysis of 4 is correct. Passed a const value won't F be deduced as const T& and be passed by reference?
– Andrew Tomazos
yesterday
See "Update regarding 4"
– Andrew Tomazos
yesterday
@AndrewTomazos Not with const mutable lambdas. Or rather it will deduce it as you say but would refuse to compile because it would discard theconstat the call site. Using latest MSVC2017, not sure about Clang/GCC as Godbolt seems not to work atm.
– Resurrection
yesterday
1
@artyr No, that is nonsense. Feel free to test it yourself, but 4 won't calloperator()&&.
– Yakk - Adam Nevraumont
yesterday
add a comment |
I do not think there is a definitive answer:
The first one copies everything you pass in which might be expensive
for capturing lambdas but otherwise provides the most flexibility:
Pros
- Const objects allowed
- Mutable objects allowed (copied)
- Copy can be elided (?)
Cons
- Copies everything you give it
- You cannot call it with an existing object such as mutable lambda without copying it in
The second one cannot be used for const objects. On the other hand
it does not copy anything and allows mutable objects:
Pros
- Mutable objects allowed
- Copies nothing
Cons
- Does not allow const objects
The third one cannot be used for mutable lambdas so is a slight
modification of the second one.
Pros
- Const objects allowed
- Copies nothing
Cons
- Cannot be called with mutable objects
The fourth one cannot be called with const objects unless you copy
them which becomes quite awkward with lambdas. You also cannot use
it with pre-existing mutable lambda object without copying it or
moving from it (losing it in the process) which is similar
limitation to 1.
Pros
- Avoids copies explicitely by forcing (requiring) move semanthics if the copy is needed
- Mutable objects allowed.
- Const objects allowed (except for mutable lambdas)
Cons
- Does not allow const mutable lambdas without a copy
- You cannot call it with an existing object such as mutable lambda
And there you have it. There is no silver bullet here and there are different pros & cons to each of these versions. I tend to lean towards the first one being the default but with certain types of capturing lambdas or bigger callables, it might become an issue. And you cannot call the 1) with the mutable object and get an expected result. As mentioned in the other answer some of these can be overcome with std::ref and other ways of manipulating the actual T type. In my experience, these tend to be the source of pretty nasty bugs though when T is then something different than one expects to achieve i.e. mutability of a copy or such.
I do not think there is a definitive answer:
The first one copies everything you pass in which might be expensive
for capturing lambdas but otherwise provides the most flexibility:
Pros
- Const objects allowed
- Mutable objects allowed (copied)
- Copy can be elided (?)
Cons
- Copies everything you give it
- You cannot call it with an existing object such as mutable lambda without copying it in
The second one cannot be used for const objects. On the other hand
it does not copy anything and allows mutable objects:
Pros
- Mutable objects allowed
- Copies nothing
Cons
- Does not allow const objects
The third one cannot be used for mutable lambdas so is a slight
modification of the second one.
Pros
- Const objects allowed
- Copies nothing
Cons
- Cannot be called with mutable objects
The fourth one cannot be called with const objects unless you copy
them which becomes quite awkward with lambdas. You also cannot use
it with pre-existing mutable lambda object without copying it or
moving from it (losing it in the process) which is similar
limitation to 1.
Pros
- Avoids copies explicitely by forcing (requiring) move semanthics if the copy is needed
- Mutable objects allowed.
- Const objects allowed (except for mutable lambdas)
Cons
- Does not allow const mutable lambdas without a copy
- You cannot call it with an existing object such as mutable lambda
And there you have it. There is no silver bullet here and there are different pros & cons to each of these versions. I tend to lean towards the first one being the default but with certain types of capturing lambdas or bigger callables, it might become an issue. And you cannot call the 1) with the mutable object and get an expected result. As mentioned in the other answer some of these can be overcome with std::ref and other ways of manipulating the actual T type. In my experience, these tend to be the source of pretty nasty bugs though when T is then something different than one expects to achieve i.e. mutability of a copy or such.
edited yesterday
JeJo
4,5173926
4,5173926
answered yesterday
ResurrectionResurrection
2,05911839
2,05911839
1
I don't think your analysis of 4 is correct. Passed a const value won't F be deduced as const T& and be passed by reference?
– Andrew Tomazos
yesterday
See "Update regarding 4"
– Andrew Tomazos
yesterday
@AndrewTomazos Not with const mutable lambdas. Or rather it will deduce it as you say but would refuse to compile because it would discard theconstat the call site. Using latest MSVC2017, not sure about Clang/GCC as Godbolt seems not to work atm.
– Resurrection
yesterday
1
@artyr No, that is nonsense. Feel free to test it yourself, but 4 won't calloperator()&&.
– Yakk - Adam Nevraumont
yesterday
add a comment |
1
I don't think your analysis of 4 is correct. Passed a const value won't F be deduced as const T& and be passed by reference?
– Andrew Tomazos
yesterday
See "Update regarding 4"
– Andrew Tomazos
yesterday
@AndrewTomazos Not with const mutable lambdas. Or rather it will deduce it as you say but would refuse to compile because it would discard theconstat the call site. Using latest MSVC2017, not sure about Clang/GCC as Godbolt seems not to work atm.
– Resurrection
yesterday
1
@artyr No, that is nonsense. Feel free to test it yourself, but 4 won't calloperator()&&.
– Yakk - Adam Nevraumont
yesterday
1
1
I don't think your analysis of 4 is correct. Passed a const value won't F be deduced as const T& and be passed by reference?
– Andrew Tomazos
yesterday
I don't think your analysis of 4 is correct. Passed a const value won't F be deduced as const T& and be passed by reference?
– Andrew Tomazos
yesterday
See "Update regarding 4"
– Andrew Tomazos
yesterday
See "Update regarding 4"
– Andrew Tomazos
yesterday
@AndrewTomazos Not with const mutable lambdas. Or rather it will deduce it as you say but would refuse to compile because it would discard the
const at the call site. Using latest MSVC2017, not sure about Clang/GCC as Godbolt seems not to work atm.– Resurrection
yesterday
@AndrewTomazos Not with const mutable lambdas. Or rather it will deduce it as you say but would refuse to compile because it would discard the
const at the call site. Using latest MSVC2017, not sure about Clang/GCC as Godbolt seems not to work atm.– Resurrection
yesterday
1
1
@artyr No, that is nonsense. Feel free to test it yourself, but 4 won't call
operator()&&.– Yakk - Adam Nevraumont
yesterday
@artyr No, that is nonsense. Feel free to test it yourself, but 4 won't call
operator()&&.– Yakk - Adam Nevraumont
yesterday
add a comment |
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%2f55674830%2fpassing-functions-in-c%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
1
go for the last one.
– Hoodi
yesterday
6
@Hoodi: Why?...
– Andrew Tomazos
yesterday
Because in your sample code, you just call f one hundred times and you have not changed F. So, go for the last one.
– Hoodi
yesterday
8
@Hoodi - You have no way to know if
fhas any state that changes by callingf(). That template accepts general functors.– StoryTeller
yesterday