How to avoid run-time checks for running parts of code that become unreachable after compilation?
My program gets a couple of Boolean variables from the user, and their values won't change afterwards. Each Boolean variable enables a part of code. Something like this:
#include <iostream>
void callback_function(bool task_1, bool task_2, bool task_3) {
if (task_1) {
std::cout << "Running task 1" << std::endl;
}
if (task_2) {
std::cout << "Running task 2" << std::endl;
}
if (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
while (true) {
callback_function(task_1, task_2, task_3);
}
return 0;
}
Now my question is, since the Boolean variables are fixed every time the program calls callback_function()
, is there a way to avoid the if
statements inside the callback function?
This is one way to avoid the run-time checks (implement a callback function for all permutations of the Boolean variables --- only two cases are shown below):
#include <functional>
#include <iostream>
void callback_function_for_tasks_1_2_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 2" << std::endl;
std::cout << "Running task 3" << std::endl;
}
void callback_function_for_tasks_1_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 3" << std::endl;
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
std::function<void()> callback_function;
if (task_1 && task_2 && task_3) {
callback_function = callback_function_for_tasks_1_2_3;
} else if (task_1 && !task_2 && task_3) {
callback_function = callback_function_for_tasks_1_3;
}
while (true) {
callback_function();
}
return 0;
}
The problem is I have to implement 2^n
different callback functions, if there are n
Boolean variables. Is there a better way to accomplish this?
c++
New contributor
|
show 4 more comments
My program gets a couple of Boolean variables from the user, and their values won't change afterwards. Each Boolean variable enables a part of code. Something like this:
#include <iostream>
void callback_function(bool task_1, bool task_2, bool task_3) {
if (task_1) {
std::cout << "Running task 1" << std::endl;
}
if (task_2) {
std::cout << "Running task 2" << std::endl;
}
if (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
while (true) {
callback_function(task_1, task_2, task_3);
}
return 0;
}
Now my question is, since the Boolean variables are fixed every time the program calls callback_function()
, is there a way to avoid the if
statements inside the callback function?
This is one way to avoid the run-time checks (implement a callback function for all permutations of the Boolean variables --- only two cases are shown below):
#include <functional>
#include <iostream>
void callback_function_for_tasks_1_2_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 2" << std::endl;
std::cout << "Running task 3" << std::endl;
}
void callback_function_for_tasks_1_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 3" << std::endl;
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
std::function<void()> callback_function;
if (task_1 && task_2 && task_3) {
callback_function = callback_function_for_tasks_1_2_3;
} else if (task_1 && !task_2 && task_3) {
callback_function = callback_function_for_tasks_1_3;
}
while (true) {
callback_function();
}
return 0;
}
The problem is I have to implement 2^n
different callback functions, if there are n
Boolean variables. Is there a better way to accomplish this?
c++
New contributor
6
If you’re interested in performance, don’t usestd::function
when a function pointer will do.
– Davis Herring
Mar 31 at 6:02
5
Have you actually measured whether these conditional statements make a difference? This looks like a pretty pointless optimization effort to me. Or, if you're trying to solve an actual problem with this, it may be the wrong approach, a so-called "XY problem". Please, as a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Mar 31 at 6:09
If you go with with the 2nd approach, I believe, you will end up doing more checks then the 1st approch. Because each compound checks you are doing in the 2nd one will computationally cost you more than the 1st. I am not sure what are you trying to accomplish here, but if your concern is that for a false flag, the statements inside the block will take time to execute, then you don't have to worry about that. Because if the flag is false, the block will not take any execution time. And checking 1 by 1 will be cheaper than the combinations.
– ABM Ruman
Mar 31 at 6:14
2
@ABMRuman He'd be doing more checks only once, not every time in the loop. If this is a long running application... One could safe quite a lot of checks if one combined the conditions inside an unsigned int/uint32_t/uint64_t (depending on number of checks) and select the function via aswitch
statement. The functions might be generated via a template function usingif constexpr
inside, so one wouldn't need to write all the functions explicitly.
– Aconcagua
Mar 31 at 6:26
Joining @UlrichEckhardt: You should first run a profiler to find the hottest spots to optimise. Optimising the called functions at the right places will most likely bring you much more performance gain than avoiding these viewif
s...
– Aconcagua
Mar 31 at 6:28
|
show 4 more comments
My program gets a couple of Boolean variables from the user, and their values won't change afterwards. Each Boolean variable enables a part of code. Something like this:
#include <iostream>
void callback_function(bool task_1, bool task_2, bool task_3) {
if (task_1) {
std::cout << "Running task 1" << std::endl;
}
if (task_2) {
std::cout << "Running task 2" << std::endl;
}
if (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
while (true) {
callback_function(task_1, task_2, task_3);
}
return 0;
}
Now my question is, since the Boolean variables are fixed every time the program calls callback_function()
, is there a way to avoid the if
statements inside the callback function?
This is one way to avoid the run-time checks (implement a callback function for all permutations of the Boolean variables --- only two cases are shown below):
#include <functional>
#include <iostream>
void callback_function_for_tasks_1_2_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 2" << std::endl;
std::cout << "Running task 3" << std::endl;
}
void callback_function_for_tasks_1_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 3" << std::endl;
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
std::function<void()> callback_function;
if (task_1 && task_2 && task_3) {
callback_function = callback_function_for_tasks_1_2_3;
} else if (task_1 && !task_2 && task_3) {
callback_function = callback_function_for_tasks_1_3;
}
while (true) {
callback_function();
}
return 0;
}
The problem is I have to implement 2^n
different callback functions, if there are n
Boolean variables. Is there a better way to accomplish this?
c++
New contributor
My program gets a couple of Boolean variables from the user, and their values won't change afterwards. Each Boolean variable enables a part of code. Something like this:
#include <iostream>
void callback_function(bool task_1, bool task_2, bool task_3) {
if (task_1) {
std::cout << "Running task 1" << std::endl;
}
if (task_2) {
std::cout << "Running task 2" << std::endl;
}
if (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
while (true) {
callback_function(task_1, task_2, task_3);
}
return 0;
}
Now my question is, since the Boolean variables are fixed every time the program calls callback_function()
, is there a way to avoid the if
statements inside the callback function?
This is one way to avoid the run-time checks (implement a callback function for all permutations of the Boolean variables --- only two cases are shown below):
#include <functional>
#include <iostream>
void callback_function_for_tasks_1_2_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 2" << std::endl;
std::cout << "Running task 3" << std::endl;
}
void callback_function_for_tasks_1_3() {
std::cout << "Running task 1" << std::endl;
std::cout << "Running task 3" << std::endl;
}
int main() {
bool task_1 = true;
bool task_2 = false;
bool task_3 = true;
std::function<void()> callback_function;
if (task_1 && task_2 && task_3) {
callback_function = callback_function_for_tasks_1_2_3;
} else if (task_1 && !task_2 && task_3) {
callback_function = callback_function_for_tasks_1_3;
}
while (true) {
callback_function();
}
return 0;
}
The problem is I have to implement 2^n
different callback functions, if there are n
Boolean variables. Is there a better way to accomplish this?
c++
c++
New contributor
New contributor
New contributor
asked Mar 31 at 5:59
Alireza ShafaeiAlireza Shafaei
362
362
New contributor
New contributor
6
If you’re interested in performance, don’t usestd::function
when a function pointer will do.
– Davis Herring
Mar 31 at 6:02
5
Have you actually measured whether these conditional statements make a difference? This looks like a pretty pointless optimization effort to me. Or, if you're trying to solve an actual problem with this, it may be the wrong approach, a so-called "XY problem". Please, as a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Mar 31 at 6:09
If you go with with the 2nd approach, I believe, you will end up doing more checks then the 1st approch. Because each compound checks you are doing in the 2nd one will computationally cost you more than the 1st. I am not sure what are you trying to accomplish here, but if your concern is that for a false flag, the statements inside the block will take time to execute, then you don't have to worry about that. Because if the flag is false, the block will not take any execution time. And checking 1 by 1 will be cheaper than the combinations.
– ABM Ruman
Mar 31 at 6:14
2
@ABMRuman He'd be doing more checks only once, not every time in the loop. If this is a long running application... One could safe quite a lot of checks if one combined the conditions inside an unsigned int/uint32_t/uint64_t (depending on number of checks) and select the function via aswitch
statement. The functions might be generated via a template function usingif constexpr
inside, so one wouldn't need to write all the functions explicitly.
– Aconcagua
Mar 31 at 6:26
Joining @UlrichEckhardt: You should first run a profiler to find the hottest spots to optimise. Optimising the called functions at the right places will most likely bring you much more performance gain than avoiding these viewif
s...
– Aconcagua
Mar 31 at 6:28
|
show 4 more comments
6
If you’re interested in performance, don’t usestd::function
when a function pointer will do.
– Davis Herring
Mar 31 at 6:02
5
Have you actually measured whether these conditional statements make a difference? This looks like a pretty pointless optimization effort to me. Or, if you're trying to solve an actual problem with this, it may be the wrong approach, a so-called "XY problem". Please, as a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Mar 31 at 6:09
If you go with with the 2nd approach, I believe, you will end up doing more checks then the 1st approch. Because each compound checks you are doing in the 2nd one will computationally cost you more than the 1st. I am not sure what are you trying to accomplish here, but if your concern is that for a false flag, the statements inside the block will take time to execute, then you don't have to worry about that. Because if the flag is false, the block will not take any execution time. And checking 1 by 1 will be cheaper than the combinations.
– ABM Ruman
Mar 31 at 6:14
2
@ABMRuman He'd be doing more checks only once, not every time in the loop. If this is a long running application... One could safe quite a lot of checks if one combined the conditions inside an unsigned int/uint32_t/uint64_t (depending on number of checks) and select the function via aswitch
statement. The functions might be generated via a template function usingif constexpr
inside, so one wouldn't need to write all the functions explicitly.
– Aconcagua
Mar 31 at 6:26
Joining @UlrichEckhardt: You should first run a profiler to find the hottest spots to optimise. Optimising the called functions at the right places will most likely bring you much more performance gain than avoiding these viewif
s...
– Aconcagua
Mar 31 at 6:28
6
6
If you’re interested in performance, don’t use
std::function
when a function pointer will do.– Davis Herring
Mar 31 at 6:02
If you’re interested in performance, don’t use
std::function
when a function pointer will do.– Davis Herring
Mar 31 at 6:02
5
5
Have you actually measured whether these conditional statements make a difference? This looks like a pretty pointless optimization effort to me. Or, if you're trying to solve an actual problem with this, it may be the wrong approach, a so-called "XY problem". Please, as a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Mar 31 at 6:09
Have you actually measured whether these conditional statements make a difference? This looks like a pretty pointless optimization effort to me. Or, if you're trying to solve an actual problem with this, it may be the wrong approach, a so-called "XY problem". Please, as a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Mar 31 at 6:09
If you go with with the 2nd approach, I believe, you will end up doing more checks then the 1st approch. Because each compound checks you are doing in the 2nd one will computationally cost you more than the 1st. I am not sure what are you trying to accomplish here, but if your concern is that for a false flag, the statements inside the block will take time to execute, then you don't have to worry about that. Because if the flag is false, the block will not take any execution time. And checking 1 by 1 will be cheaper than the combinations.
– ABM Ruman
Mar 31 at 6:14
If you go with with the 2nd approach, I believe, you will end up doing more checks then the 1st approch. Because each compound checks you are doing in the 2nd one will computationally cost you more than the 1st. I am not sure what are you trying to accomplish here, but if your concern is that for a false flag, the statements inside the block will take time to execute, then you don't have to worry about that. Because if the flag is false, the block will not take any execution time. And checking 1 by 1 will be cheaper than the combinations.
– ABM Ruman
Mar 31 at 6:14
2
2
@ABMRuman He'd be doing more checks only once, not every time in the loop. If this is a long running application... One could safe quite a lot of checks if one combined the conditions inside an unsigned int/uint32_t/uint64_t (depending on number of checks) and select the function via a
switch
statement. The functions might be generated via a template function using if constexpr
inside, so one wouldn't need to write all the functions explicitly.– Aconcagua
Mar 31 at 6:26
@ABMRuman He'd be doing more checks only once, not every time in the loop. If this is a long running application... One could safe quite a lot of checks if one combined the conditions inside an unsigned int/uint32_t/uint64_t (depending on number of checks) and select the function via a
switch
statement. The functions might be generated via a template function using if constexpr
inside, so one wouldn't need to write all the functions explicitly.– Aconcagua
Mar 31 at 6:26
Joining @UlrichEckhardt: You should first run a profiler to find the hottest spots to optimise. Optimising the called functions at the right places will most likely bring you much more performance gain than avoiding these view
if
s...– Aconcagua
Mar 31 at 6:28
Joining @UlrichEckhardt: You should first run a profiler to find the hottest spots to optimise. Optimising the called functions at the right places will most likely bring you much more performance gain than avoiding these view
if
s...– Aconcagua
Mar 31 at 6:28
|
show 4 more comments
3 Answers
3
active
oldest
votes
Ensuring that if statements are evaluated at compile time
C++17 introduces if constexpr
, which does exactly this:
template<bool task_1, bool task_2, bool task_3>
void callback_function() {
if constexpr (task_1) {
std::cout << "Running task 1" << std::endl;
}
if constexpr (task_2) {
std::cout << "Running task 2" << std::endl;
}
if constexpr (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
If you have optimizations enabled, if constexpr
isn't necessary. Even if you use a regular if
instead of if constexpr
, because the bools are now templated, the compiler will be able to eliminate the if
statements entirely, and just run the tasks. If you look at the assembly produced here, you'll see that even at -O1
, there are no if statements in any of the callback
functions.
We can now use callback_function
directly as a function pointer, avoiding function<void()>
:
int main() {
using callback_t = void(*)();
callback_t func = callback_function<true, false, true>;
// Do stuff with func
}
We can also name the bool
s by assigning them to constexpr variables:
int main() {
using callback_t = void(*)();
constexpr bool do_task1 = true;
constexpr bool do_task2 = false;
constexpr bool do_task3 = true;
callback_t func = callback_function<do_task1, do_task2, do_task3>;
// Do stuff with func
}
Automatically creating a lookup table of all possible callback functions
You mentioned choosing between different callback functions at runtime. We can do this pretty easily with a lookup table, and we can use templates to automatically create a lookup table of all possible callback functions.
The first step is to get a callback function from a particular index:
// void(*)() is ugly to type, so I alias it
using callback_t = void(*)();
// Unpacks the bits
template<size_t index>
constexpr auto getCallbackFromIndex() -> callback_t
{
constexpr bool do_task1 = (index & 4) != 0;
constexpr bool do_task2 = (index & 2) != 0;
constexpr bool do_task3 = (index & 1) != 0;
return callback_function<do_task1, do_task2, do_task3>;
}
Once we can do that, we can write a function to create a lookup table from a bunch of indexes. Our lookup table will just be a std::array
.
// Create a std::array based on a list of flags
// See https://en.cppreference.com/w/cpp/utility/integer_sequence
// For more information
template<size_t... Indexes>
constexpr auto getVersionLookup(std::index_sequence<Indexes...>)
-> std::array<callback_t, sizeof...(Indexes)>
{
return {getCallbackFromIndex<Indexes>()...};
}
// Makes a lookup table containing all 8 possible callback functions
constexpr auto callbackLookupTable =
getVersionLookup(std::make_index_sequence<8>());
Here, callbackLookupTable
contains all 8 possible callback functions, where callbackLookupTable[i]
expands the bits of i
to get the callback. For example, if i == 6
, then i
's bits are 110
in binary, so
callbackLookupTable[6]
is callback_function<true, true, false>
Using the lookup table at runtime
Using the lookup table is really simple. We can get an index from a bunch of bool
s by bitshifting:
callback_t getCallbackBasedOnTasks(bool task1, bool task2, bool task3) {
// Get the index based on bit shifting
int index = ((int)task1 << 2) + ((int)task2 << 1) + ((int)task3);
// return the correct callback
return callbackLookupTable[index];
}
Example demonstrating how to read in tasks
We can get the bool
s at runtime now, and just call getCallbackBasedOnTasks
to get the correct callback
int main() {
bool t1, t2, t3;
// Read in bools
std::cin >> t1 >> t2 >> t3;
// Get the callback
callback_t func = getCallbackBasedOnTasks(t1, t2, t3);
// Invoke the callback
func();
}
Theconstexpr
is IMHO a red herring, the important part is the use of template parameters which are evaluated at compile time. Any halfway-decent compiler is able to figure this out even without theseconsexpr
hints.
– Ulrich Eckhardt
Mar 31 at 6:31
I updated the answer explaining how to automatically generate a list of all possible callback functions. You can find the right one just by packing the bools into the bits of the index
– Jorge Perez
Mar 31 at 6:50
The lookup table is a runtime solution. You can get the right function just by indexing into it
– Jorge Perez
Mar 31 at 6:53
I added code showing exactly how to do that
– Jorge Perez
2 days ago
1
(@$#*!) – can't find anything to criticise any more... Just kidding. But the automatically created lookup table is great, far better than my originally proposedswitch
statement...
– Aconcagua
2 days ago
|
show 1 more comment
Leave the code as it is.
Execution time of an "if" compared to writing to std::out is practically zero, so you are arguing over nothing. Well, unless you spend some time measuring the execution time as it is, and with the if's removed according to the values of the three constants, and found that there is a real difference.
At most, you might make the function inline or static, and the compiler will probably realise the arguments are always the same when optimisation is turned on. (My compiler would give a warning that you are using a function without a prototype, which means you should have either put a prototype into a header file, telling the compiler to expect calls from other call sites, or you should have made it static, telling the compiler that it knows all the calls and can use static analysis for optimisations).
And what you think is a constant, might not stay a constant forever. The original code will work. Any new code most likely won't.
If the call is inlined into the loop, the compiler might hoist the tests, but it’s unlikely for more than a variable or two because of the code size increase.
– Davis Herring
4 hours ago
add a comment |
Short of JIT compilation, you can’t do better than your 2^n functions (and the resulting binary size). You can of course use a template to avoid writing them all out. To prevent the source from scaling exponentially just from selecting the correct implementation, you can write a recursive dispatcher (demo):
template<bool... BB>
auto g() {return f<BB...>;}
template<bool... BB,class... TT>
auto g(bool b,TT... tt)
{return b ? g<BB...,true>(tt...) : g<BB...,false>(tt...);}
If you know something at compiletime, it's easy to template it. Especially in the OP's case.
– Jorge Perez
Mar 31 at 6:20
@JorgePerez: I did say that you could use a template. I do realize now that you can put some of theif
s inside intermediate templates; I’ll edit that in.
– Davis Herring
2 days ago
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
});
}
});
Alireza Shafaei is a new contributor. Be nice, and check out our Code of Conduct.
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%2f55438306%2fhow-to-avoid-run-time-checks-for-running-parts-of-code-that-become-unreachable-a%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
Ensuring that if statements are evaluated at compile time
C++17 introduces if constexpr
, which does exactly this:
template<bool task_1, bool task_2, bool task_3>
void callback_function() {
if constexpr (task_1) {
std::cout << "Running task 1" << std::endl;
}
if constexpr (task_2) {
std::cout << "Running task 2" << std::endl;
}
if constexpr (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
If you have optimizations enabled, if constexpr
isn't necessary. Even if you use a regular if
instead of if constexpr
, because the bools are now templated, the compiler will be able to eliminate the if
statements entirely, and just run the tasks. If you look at the assembly produced here, you'll see that even at -O1
, there are no if statements in any of the callback
functions.
We can now use callback_function
directly as a function pointer, avoiding function<void()>
:
int main() {
using callback_t = void(*)();
callback_t func = callback_function<true, false, true>;
// Do stuff with func
}
We can also name the bool
s by assigning them to constexpr variables:
int main() {
using callback_t = void(*)();
constexpr bool do_task1 = true;
constexpr bool do_task2 = false;
constexpr bool do_task3 = true;
callback_t func = callback_function<do_task1, do_task2, do_task3>;
// Do stuff with func
}
Automatically creating a lookup table of all possible callback functions
You mentioned choosing between different callback functions at runtime. We can do this pretty easily with a lookup table, and we can use templates to automatically create a lookup table of all possible callback functions.
The first step is to get a callback function from a particular index:
// void(*)() is ugly to type, so I alias it
using callback_t = void(*)();
// Unpacks the bits
template<size_t index>
constexpr auto getCallbackFromIndex() -> callback_t
{
constexpr bool do_task1 = (index & 4) != 0;
constexpr bool do_task2 = (index & 2) != 0;
constexpr bool do_task3 = (index & 1) != 0;
return callback_function<do_task1, do_task2, do_task3>;
}
Once we can do that, we can write a function to create a lookup table from a bunch of indexes. Our lookup table will just be a std::array
.
// Create a std::array based on a list of flags
// See https://en.cppreference.com/w/cpp/utility/integer_sequence
// For more information
template<size_t... Indexes>
constexpr auto getVersionLookup(std::index_sequence<Indexes...>)
-> std::array<callback_t, sizeof...(Indexes)>
{
return {getCallbackFromIndex<Indexes>()...};
}
// Makes a lookup table containing all 8 possible callback functions
constexpr auto callbackLookupTable =
getVersionLookup(std::make_index_sequence<8>());
Here, callbackLookupTable
contains all 8 possible callback functions, where callbackLookupTable[i]
expands the bits of i
to get the callback. For example, if i == 6
, then i
's bits are 110
in binary, so
callbackLookupTable[6]
is callback_function<true, true, false>
Using the lookup table at runtime
Using the lookup table is really simple. We can get an index from a bunch of bool
s by bitshifting:
callback_t getCallbackBasedOnTasks(bool task1, bool task2, bool task3) {
// Get the index based on bit shifting
int index = ((int)task1 << 2) + ((int)task2 << 1) + ((int)task3);
// return the correct callback
return callbackLookupTable[index];
}
Example demonstrating how to read in tasks
We can get the bool
s at runtime now, and just call getCallbackBasedOnTasks
to get the correct callback
int main() {
bool t1, t2, t3;
// Read in bools
std::cin >> t1 >> t2 >> t3;
// Get the callback
callback_t func = getCallbackBasedOnTasks(t1, t2, t3);
// Invoke the callback
func();
}
Theconstexpr
is IMHO a red herring, the important part is the use of template parameters which are evaluated at compile time. Any halfway-decent compiler is able to figure this out even without theseconsexpr
hints.
– Ulrich Eckhardt
Mar 31 at 6:31
I updated the answer explaining how to automatically generate a list of all possible callback functions. You can find the right one just by packing the bools into the bits of the index
– Jorge Perez
Mar 31 at 6:50
The lookup table is a runtime solution. You can get the right function just by indexing into it
– Jorge Perez
Mar 31 at 6:53
I added code showing exactly how to do that
– Jorge Perez
2 days ago
1
(@$#*!) – can't find anything to criticise any more... Just kidding. But the automatically created lookup table is great, far better than my originally proposedswitch
statement...
– Aconcagua
2 days ago
|
show 1 more comment
Ensuring that if statements are evaluated at compile time
C++17 introduces if constexpr
, which does exactly this:
template<bool task_1, bool task_2, bool task_3>
void callback_function() {
if constexpr (task_1) {
std::cout << "Running task 1" << std::endl;
}
if constexpr (task_2) {
std::cout << "Running task 2" << std::endl;
}
if constexpr (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
If you have optimizations enabled, if constexpr
isn't necessary. Even if you use a regular if
instead of if constexpr
, because the bools are now templated, the compiler will be able to eliminate the if
statements entirely, and just run the tasks. If you look at the assembly produced here, you'll see that even at -O1
, there are no if statements in any of the callback
functions.
We can now use callback_function
directly as a function pointer, avoiding function<void()>
:
int main() {
using callback_t = void(*)();
callback_t func = callback_function<true, false, true>;
// Do stuff with func
}
We can also name the bool
s by assigning them to constexpr variables:
int main() {
using callback_t = void(*)();
constexpr bool do_task1 = true;
constexpr bool do_task2 = false;
constexpr bool do_task3 = true;
callback_t func = callback_function<do_task1, do_task2, do_task3>;
// Do stuff with func
}
Automatically creating a lookup table of all possible callback functions
You mentioned choosing between different callback functions at runtime. We can do this pretty easily with a lookup table, and we can use templates to automatically create a lookup table of all possible callback functions.
The first step is to get a callback function from a particular index:
// void(*)() is ugly to type, so I alias it
using callback_t = void(*)();
// Unpacks the bits
template<size_t index>
constexpr auto getCallbackFromIndex() -> callback_t
{
constexpr bool do_task1 = (index & 4) != 0;
constexpr bool do_task2 = (index & 2) != 0;
constexpr bool do_task3 = (index & 1) != 0;
return callback_function<do_task1, do_task2, do_task3>;
}
Once we can do that, we can write a function to create a lookup table from a bunch of indexes. Our lookup table will just be a std::array
.
// Create a std::array based on a list of flags
// See https://en.cppreference.com/w/cpp/utility/integer_sequence
// For more information
template<size_t... Indexes>
constexpr auto getVersionLookup(std::index_sequence<Indexes...>)
-> std::array<callback_t, sizeof...(Indexes)>
{
return {getCallbackFromIndex<Indexes>()...};
}
// Makes a lookup table containing all 8 possible callback functions
constexpr auto callbackLookupTable =
getVersionLookup(std::make_index_sequence<8>());
Here, callbackLookupTable
contains all 8 possible callback functions, where callbackLookupTable[i]
expands the bits of i
to get the callback. For example, if i == 6
, then i
's bits are 110
in binary, so
callbackLookupTable[6]
is callback_function<true, true, false>
Using the lookup table at runtime
Using the lookup table is really simple. We can get an index from a bunch of bool
s by bitshifting:
callback_t getCallbackBasedOnTasks(bool task1, bool task2, bool task3) {
// Get the index based on bit shifting
int index = ((int)task1 << 2) + ((int)task2 << 1) + ((int)task3);
// return the correct callback
return callbackLookupTable[index];
}
Example demonstrating how to read in tasks
We can get the bool
s at runtime now, and just call getCallbackBasedOnTasks
to get the correct callback
int main() {
bool t1, t2, t3;
// Read in bools
std::cin >> t1 >> t2 >> t3;
// Get the callback
callback_t func = getCallbackBasedOnTasks(t1, t2, t3);
// Invoke the callback
func();
}
Theconstexpr
is IMHO a red herring, the important part is the use of template parameters which are evaluated at compile time. Any halfway-decent compiler is able to figure this out even without theseconsexpr
hints.
– Ulrich Eckhardt
Mar 31 at 6:31
I updated the answer explaining how to automatically generate a list of all possible callback functions. You can find the right one just by packing the bools into the bits of the index
– Jorge Perez
Mar 31 at 6:50
The lookup table is a runtime solution. You can get the right function just by indexing into it
– Jorge Perez
Mar 31 at 6:53
I added code showing exactly how to do that
– Jorge Perez
2 days ago
1
(@$#*!) – can't find anything to criticise any more... Just kidding. But the automatically created lookup table is great, far better than my originally proposedswitch
statement...
– Aconcagua
2 days ago
|
show 1 more comment
Ensuring that if statements are evaluated at compile time
C++17 introduces if constexpr
, which does exactly this:
template<bool task_1, bool task_2, bool task_3>
void callback_function() {
if constexpr (task_1) {
std::cout << "Running task 1" << std::endl;
}
if constexpr (task_2) {
std::cout << "Running task 2" << std::endl;
}
if constexpr (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
If you have optimizations enabled, if constexpr
isn't necessary. Even if you use a regular if
instead of if constexpr
, because the bools are now templated, the compiler will be able to eliminate the if
statements entirely, and just run the tasks. If you look at the assembly produced here, you'll see that even at -O1
, there are no if statements in any of the callback
functions.
We can now use callback_function
directly as a function pointer, avoiding function<void()>
:
int main() {
using callback_t = void(*)();
callback_t func = callback_function<true, false, true>;
// Do stuff with func
}
We can also name the bool
s by assigning them to constexpr variables:
int main() {
using callback_t = void(*)();
constexpr bool do_task1 = true;
constexpr bool do_task2 = false;
constexpr bool do_task3 = true;
callback_t func = callback_function<do_task1, do_task2, do_task3>;
// Do stuff with func
}
Automatically creating a lookup table of all possible callback functions
You mentioned choosing between different callback functions at runtime. We can do this pretty easily with a lookup table, and we can use templates to automatically create a lookup table of all possible callback functions.
The first step is to get a callback function from a particular index:
// void(*)() is ugly to type, so I alias it
using callback_t = void(*)();
// Unpacks the bits
template<size_t index>
constexpr auto getCallbackFromIndex() -> callback_t
{
constexpr bool do_task1 = (index & 4) != 0;
constexpr bool do_task2 = (index & 2) != 0;
constexpr bool do_task3 = (index & 1) != 0;
return callback_function<do_task1, do_task2, do_task3>;
}
Once we can do that, we can write a function to create a lookup table from a bunch of indexes. Our lookup table will just be a std::array
.
// Create a std::array based on a list of flags
// See https://en.cppreference.com/w/cpp/utility/integer_sequence
// For more information
template<size_t... Indexes>
constexpr auto getVersionLookup(std::index_sequence<Indexes...>)
-> std::array<callback_t, sizeof...(Indexes)>
{
return {getCallbackFromIndex<Indexes>()...};
}
// Makes a lookup table containing all 8 possible callback functions
constexpr auto callbackLookupTable =
getVersionLookup(std::make_index_sequence<8>());
Here, callbackLookupTable
contains all 8 possible callback functions, where callbackLookupTable[i]
expands the bits of i
to get the callback. For example, if i == 6
, then i
's bits are 110
in binary, so
callbackLookupTable[6]
is callback_function<true, true, false>
Using the lookup table at runtime
Using the lookup table is really simple. We can get an index from a bunch of bool
s by bitshifting:
callback_t getCallbackBasedOnTasks(bool task1, bool task2, bool task3) {
// Get the index based on bit shifting
int index = ((int)task1 << 2) + ((int)task2 << 1) + ((int)task3);
// return the correct callback
return callbackLookupTable[index];
}
Example demonstrating how to read in tasks
We can get the bool
s at runtime now, and just call getCallbackBasedOnTasks
to get the correct callback
int main() {
bool t1, t2, t3;
// Read in bools
std::cin >> t1 >> t2 >> t3;
// Get the callback
callback_t func = getCallbackBasedOnTasks(t1, t2, t3);
// Invoke the callback
func();
}
Ensuring that if statements are evaluated at compile time
C++17 introduces if constexpr
, which does exactly this:
template<bool task_1, bool task_2, bool task_3>
void callback_function() {
if constexpr (task_1) {
std::cout << "Running task 1" << std::endl;
}
if constexpr (task_2) {
std::cout << "Running task 2" << std::endl;
}
if constexpr (task_3) {
std::cout << "Running task 3" << std::endl;
}
}
If you have optimizations enabled, if constexpr
isn't necessary. Even if you use a regular if
instead of if constexpr
, because the bools are now templated, the compiler will be able to eliminate the if
statements entirely, and just run the tasks. If you look at the assembly produced here, you'll see that even at -O1
, there are no if statements in any of the callback
functions.
We can now use callback_function
directly as a function pointer, avoiding function<void()>
:
int main() {
using callback_t = void(*)();
callback_t func = callback_function<true, false, true>;
// Do stuff with func
}
We can also name the bool
s by assigning them to constexpr variables:
int main() {
using callback_t = void(*)();
constexpr bool do_task1 = true;
constexpr bool do_task2 = false;
constexpr bool do_task3 = true;
callback_t func = callback_function<do_task1, do_task2, do_task3>;
// Do stuff with func
}
Automatically creating a lookup table of all possible callback functions
You mentioned choosing between different callback functions at runtime. We can do this pretty easily with a lookup table, and we can use templates to automatically create a lookup table of all possible callback functions.
The first step is to get a callback function from a particular index:
// void(*)() is ugly to type, so I alias it
using callback_t = void(*)();
// Unpacks the bits
template<size_t index>
constexpr auto getCallbackFromIndex() -> callback_t
{
constexpr bool do_task1 = (index & 4) != 0;
constexpr bool do_task2 = (index & 2) != 0;
constexpr bool do_task3 = (index & 1) != 0;
return callback_function<do_task1, do_task2, do_task3>;
}
Once we can do that, we can write a function to create a lookup table from a bunch of indexes. Our lookup table will just be a std::array
.
// Create a std::array based on a list of flags
// See https://en.cppreference.com/w/cpp/utility/integer_sequence
// For more information
template<size_t... Indexes>
constexpr auto getVersionLookup(std::index_sequence<Indexes...>)
-> std::array<callback_t, sizeof...(Indexes)>
{
return {getCallbackFromIndex<Indexes>()...};
}
// Makes a lookup table containing all 8 possible callback functions
constexpr auto callbackLookupTable =
getVersionLookup(std::make_index_sequence<8>());
Here, callbackLookupTable
contains all 8 possible callback functions, where callbackLookupTable[i]
expands the bits of i
to get the callback. For example, if i == 6
, then i
's bits are 110
in binary, so
callbackLookupTable[6]
is callback_function<true, true, false>
Using the lookup table at runtime
Using the lookup table is really simple. We can get an index from a bunch of bool
s by bitshifting:
callback_t getCallbackBasedOnTasks(bool task1, bool task2, bool task3) {
// Get the index based on bit shifting
int index = ((int)task1 << 2) + ((int)task2 << 1) + ((int)task3);
// return the correct callback
return callbackLookupTable[index];
}
Example demonstrating how to read in tasks
We can get the bool
s at runtime now, and just call getCallbackBasedOnTasks
to get the correct callback
int main() {
bool t1, t2, t3;
// Read in bools
std::cin >> t1 >> t2 >> t3;
// Get the callback
callback_t func = getCallbackBasedOnTasks(t1, t2, t3);
// Invoke the callback
func();
}
edited 2 days ago
answered Mar 31 at 6:16
Jorge PerezJorge Perez
1,243416
1,243416
Theconstexpr
is IMHO a red herring, the important part is the use of template parameters which are evaluated at compile time. Any halfway-decent compiler is able to figure this out even without theseconsexpr
hints.
– Ulrich Eckhardt
Mar 31 at 6:31
I updated the answer explaining how to automatically generate a list of all possible callback functions. You can find the right one just by packing the bools into the bits of the index
– Jorge Perez
Mar 31 at 6:50
The lookup table is a runtime solution. You can get the right function just by indexing into it
– Jorge Perez
Mar 31 at 6:53
I added code showing exactly how to do that
– Jorge Perez
2 days ago
1
(@$#*!) – can't find anything to criticise any more... Just kidding. But the automatically created lookup table is great, far better than my originally proposedswitch
statement...
– Aconcagua
2 days ago
|
show 1 more comment
Theconstexpr
is IMHO a red herring, the important part is the use of template parameters which are evaluated at compile time. Any halfway-decent compiler is able to figure this out even without theseconsexpr
hints.
– Ulrich Eckhardt
Mar 31 at 6:31
I updated the answer explaining how to automatically generate a list of all possible callback functions. You can find the right one just by packing the bools into the bits of the index
– Jorge Perez
Mar 31 at 6:50
The lookup table is a runtime solution. You can get the right function just by indexing into it
– Jorge Perez
Mar 31 at 6:53
I added code showing exactly how to do that
– Jorge Perez
2 days ago
1
(@$#*!) – can't find anything to criticise any more... Just kidding. But the automatically created lookup table is great, far better than my originally proposedswitch
statement...
– Aconcagua
2 days ago
The
constexpr
is IMHO a red herring, the important part is the use of template parameters which are evaluated at compile time. Any halfway-decent compiler is able to figure this out even without these consexpr
hints.– Ulrich Eckhardt
Mar 31 at 6:31
The
constexpr
is IMHO a red herring, the important part is the use of template parameters which are evaluated at compile time. Any halfway-decent compiler is able to figure this out even without these consexpr
hints.– Ulrich Eckhardt
Mar 31 at 6:31
I updated the answer explaining how to automatically generate a list of all possible callback functions. You can find the right one just by packing the bools into the bits of the index
– Jorge Perez
Mar 31 at 6:50
I updated the answer explaining how to automatically generate a list of all possible callback functions. You can find the right one just by packing the bools into the bits of the index
– Jorge Perez
Mar 31 at 6:50
The lookup table is a runtime solution. You can get the right function just by indexing into it
– Jorge Perez
Mar 31 at 6:53
The lookup table is a runtime solution. You can get the right function just by indexing into it
– Jorge Perez
Mar 31 at 6:53
I added code showing exactly how to do that
– Jorge Perez
2 days ago
I added code showing exactly how to do that
– Jorge Perez
2 days ago
1
1
(@$#*!) – can't find anything to criticise any more... Just kidding. But the automatically created lookup table is great, far better than my originally proposed
switch
statement...– Aconcagua
2 days ago
(@$#*!) – can't find anything to criticise any more... Just kidding. But the automatically created lookup table is great, far better than my originally proposed
switch
statement...– Aconcagua
2 days ago
|
show 1 more comment
Leave the code as it is.
Execution time of an "if" compared to writing to std::out is practically zero, so you are arguing over nothing. Well, unless you spend some time measuring the execution time as it is, and with the if's removed according to the values of the three constants, and found that there is a real difference.
At most, you might make the function inline or static, and the compiler will probably realise the arguments are always the same when optimisation is turned on. (My compiler would give a warning that you are using a function without a prototype, which means you should have either put a prototype into a header file, telling the compiler to expect calls from other call sites, or you should have made it static, telling the compiler that it knows all the calls and can use static analysis for optimisations).
And what you think is a constant, might not stay a constant forever. The original code will work. Any new code most likely won't.
If the call is inlined into the loop, the compiler might hoist the tests, but it’s unlikely for more than a variable or two because of the code size increase.
– Davis Herring
4 hours ago
add a comment |
Leave the code as it is.
Execution time of an "if" compared to writing to std::out is practically zero, so you are arguing over nothing. Well, unless you spend some time measuring the execution time as it is, and with the if's removed according to the values of the three constants, and found that there is a real difference.
At most, you might make the function inline or static, and the compiler will probably realise the arguments are always the same when optimisation is turned on. (My compiler would give a warning that you are using a function without a prototype, which means you should have either put a prototype into a header file, telling the compiler to expect calls from other call sites, or you should have made it static, telling the compiler that it knows all the calls and can use static analysis for optimisations).
And what you think is a constant, might not stay a constant forever. The original code will work. Any new code most likely won't.
If the call is inlined into the loop, the compiler might hoist the tests, but it’s unlikely for more than a variable or two because of the code size increase.
– Davis Herring
4 hours ago
add a comment |
Leave the code as it is.
Execution time of an "if" compared to writing to std::out is practically zero, so you are arguing over nothing. Well, unless you spend some time measuring the execution time as it is, and with the if's removed according to the values of the three constants, and found that there is a real difference.
At most, you might make the function inline or static, and the compiler will probably realise the arguments are always the same when optimisation is turned on. (My compiler would give a warning that you are using a function without a prototype, which means you should have either put a prototype into a header file, telling the compiler to expect calls from other call sites, or you should have made it static, telling the compiler that it knows all the calls and can use static analysis for optimisations).
And what you think is a constant, might not stay a constant forever. The original code will work. Any new code most likely won't.
Leave the code as it is.
Execution time of an "if" compared to writing to std::out is practically zero, so you are arguing over nothing. Well, unless you spend some time measuring the execution time as it is, and with the if's removed according to the values of the three constants, and found that there is a real difference.
At most, you might make the function inline or static, and the compiler will probably realise the arguments are always the same when optimisation is turned on. (My compiler would give a warning that you are using a function without a prototype, which means you should have either put a prototype into a header file, telling the compiler to expect calls from other call sites, or you should have made it static, telling the compiler that it knows all the calls and can use static analysis for optimisations).
And what you think is a constant, might not stay a constant forever. The original code will work. Any new code most likely won't.
answered 2 days ago
gnasher729gnasher729
42.1k44878
42.1k44878
If the call is inlined into the loop, the compiler might hoist the tests, but it’s unlikely for more than a variable or two because of the code size increase.
– Davis Herring
4 hours ago
add a comment |
If the call is inlined into the loop, the compiler might hoist the tests, but it’s unlikely for more than a variable or two because of the code size increase.
– Davis Herring
4 hours ago
If the call is inlined into the loop, the compiler might hoist the tests, but it’s unlikely for more than a variable or two because of the code size increase.
– Davis Herring
4 hours ago
If the call is inlined into the loop, the compiler might hoist the tests, but it’s unlikely for more than a variable or two because of the code size increase.
– Davis Herring
4 hours ago
add a comment |
Short of JIT compilation, you can’t do better than your 2^n functions (and the resulting binary size). You can of course use a template to avoid writing them all out. To prevent the source from scaling exponentially just from selecting the correct implementation, you can write a recursive dispatcher (demo):
template<bool... BB>
auto g() {return f<BB...>;}
template<bool... BB,class... TT>
auto g(bool b,TT... tt)
{return b ? g<BB...,true>(tt...) : g<BB...,false>(tt...);}
If you know something at compiletime, it's easy to template it. Especially in the OP's case.
– Jorge Perez
Mar 31 at 6:20
@JorgePerez: I did say that you could use a template. I do realize now that you can put some of theif
s inside intermediate templates; I’ll edit that in.
– Davis Herring
2 days ago
add a comment |
Short of JIT compilation, you can’t do better than your 2^n functions (and the resulting binary size). You can of course use a template to avoid writing them all out. To prevent the source from scaling exponentially just from selecting the correct implementation, you can write a recursive dispatcher (demo):
template<bool... BB>
auto g() {return f<BB...>;}
template<bool... BB,class... TT>
auto g(bool b,TT... tt)
{return b ? g<BB...,true>(tt...) : g<BB...,false>(tt...);}
If you know something at compiletime, it's easy to template it. Especially in the OP's case.
– Jorge Perez
Mar 31 at 6:20
@JorgePerez: I did say that you could use a template. I do realize now that you can put some of theif
s inside intermediate templates; I’ll edit that in.
– Davis Herring
2 days ago
add a comment |
Short of JIT compilation, you can’t do better than your 2^n functions (and the resulting binary size). You can of course use a template to avoid writing them all out. To prevent the source from scaling exponentially just from selecting the correct implementation, you can write a recursive dispatcher (demo):
template<bool... BB>
auto g() {return f<BB...>;}
template<bool... BB,class... TT>
auto g(bool b,TT... tt)
{return b ? g<BB...,true>(tt...) : g<BB...,false>(tt...);}
Short of JIT compilation, you can’t do better than your 2^n functions (and the resulting binary size). You can of course use a template to avoid writing them all out. To prevent the source from scaling exponentially just from selecting the correct implementation, you can write a recursive dispatcher (demo):
template<bool... BB>
auto g() {return f<BB...>;}
template<bool... BB,class... TT>
auto g(bool b,TT... tt)
{return b ? g<BB...,true>(tt...) : g<BB...,false>(tt...);}
edited yesterday
answered Mar 31 at 6:04
Davis HerringDavis Herring
8,9121736
8,9121736
If you know something at compiletime, it's easy to template it. Especially in the OP's case.
– Jorge Perez
Mar 31 at 6:20
@JorgePerez: I did say that you could use a template. I do realize now that you can put some of theif
s inside intermediate templates; I’ll edit that in.
– Davis Herring
2 days ago
add a comment |
If you know something at compiletime, it's easy to template it. Especially in the OP's case.
– Jorge Perez
Mar 31 at 6:20
@JorgePerez: I did say that you could use a template. I do realize now that you can put some of theif
s inside intermediate templates; I’ll edit that in.
– Davis Herring
2 days ago
If you know something at compiletime, it's easy to template it. Especially in the OP's case.
– Jorge Perez
Mar 31 at 6:20
If you know something at compiletime, it's easy to template it. Especially in the OP's case.
– Jorge Perez
Mar 31 at 6:20
@JorgePerez: I did say that you could use a template. I do realize now that you can put some of the
if
s inside intermediate templates; I’ll edit that in.– Davis Herring
2 days ago
@JorgePerez: I did say that you could use a template. I do realize now that you can put some of the
if
s inside intermediate templates; I’ll edit that in.– Davis Herring
2 days ago
add a comment |
Alireza Shafaei is a new contributor. Be nice, and check out our Code of Conduct.
Alireza Shafaei is a new contributor. Be nice, and check out our Code of Conduct.
Alireza Shafaei is a new contributor. Be nice, and check out our Code of Conduct.
Alireza Shafaei is a new contributor. Be nice, and check out our Code of Conduct.
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%2f55438306%2fhow-to-avoid-run-time-checks-for-running-parts-of-code-that-become-unreachable-a%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
6
If you’re interested in performance, don’t use
std::function
when a function pointer will do.– Davis Herring
Mar 31 at 6:02
5
Have you actually measured whether these conditional statements make a difference? This looks like a pretty pointless optimization effort to me. Or, if you're trying to solve an actual problem with this, it may be the wrong approach, a so-called "XY problem". Please, as a new user, also take the tour and read How to Ask.
– Ulrich Eckhardt
Mar 31 at 6:09
If you go with with the 2nd approach, I believe, you will end up doing more checks then the 1st approch. Because each compound checks you are doing in the 2nd one will computationally cost you more than the 1st. I am not sure what are you trying to accomplish here, but if your concern is that for a false flag, the statements inside the block will take time to execute, then you don't have to worry about that. Because if the flag is false, the block will not take any execution time. And checking 1 by 1 will be cheaper than the combinations.
– ABM Ruman
Mar 31 at 6:14
2
@ABMRuman He'd be doing more checks only once, not every time in the loop. If this is a long running application... One could safe quite a lot of checks if one combined the conditions inside an unsigned int/uint32_t/uint64_t (depending on number of checks) and select the function via a
switch
statement. The functions might be generated via a template function usingif constexpr
inside, so one wouldn't need to write all the functions explicitly.– Aconcagua
Mar 31 at 6:26
Joining @UlrichEckhardt: You should first run a profiler to find the hottest spots to optimise. Optimising the called functions at the right places will most likely bring you much more performance gain than avoiding these view
if
s...– Aconcagua
Mar 31 at 6:28