How to avoid run-time checks for running parts of code that become unreachable after compilation? The Next CEO of Stack OverflowHow can I profile C++ code running on Linux?Counting the total of same running processes in C++Usage of this next_combination codeIdentify objects in boost::shared_ptr<boost::thread>How C++ reference worksNamespaces and the Pre-Processorstd::atomic_is_lock_free(shared_ptr<T>*) didn't compileCleaning data after exception on class constructorTwo-level bind fails on GCC/libstdc++ and Clang/libc++How do i read bool value using std::istream

Why the difference in type-inference over the as-pattern in two similar function definitions?

Where do students learn to solve polynomial equations these days?

Running a General Election and the European Elections together

Do I need to write [sic] when a number is less than 10 but isn't written out?

How to write a definition with variants?

What did we know about the Kessel run before the prequels?

Grabbing quick drinks

Is it professional to write unrelated content in an almost-empty email?

How many extra stops do monopods offer for tele photographs?

Domestic-to-international connection at Orlando (MCO)

Would this house-rule that treats advantage as a +1 to the roll instead (and disadvantage as -1) and allows them to stack be balanced?

Prepend last line of stdin to entire stdin

Is it possible to replace duplicates of a character with one character using tr

Example of a Mathematician/Physicist whose Other Publications during their PhD eclipsed their PhD Thesis

Axiom Schema vs Axiom

0-rank tensor vs vector in 1D

Is the D&D universe the same as the Forgotten Realms universe?

How to edit “Name” property in GCI output?

Necessary condition on homology group for a set to be contractible

What connection does MS Office have to Netscape Navigator?

Why, when going from special to general relativity, do we just replace partial derivatives with covariant derivatives?

Can MTA send mail via a relay without being told so?

Why do remote US companies require working in the US?

Are police here, aren't itthey?



How to avoid run-time checks for running parts of code that become unreachable after compilation?



The Next CEO of Stack OverflowHow can I profile C++ code running on Linux?Counting the total of same running processes in C++Usage of this next_combination codeIdentify objects in boost::shared_ptr<boost::thread>How C++ reference worksNamespaces and the Pre-Processorstd::atomic_is_lock_free(shared_ptr<T>*) didn't compileCleaning data after exception on class constructorTwo-level bind fails on GCC/libstdc++ and Clang/libc++How do i read bool value using std::istream










7















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?










share|improve this question







New contributor




Alireza Shafaei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 5





    If you’re interested in performance, don’t use std::function when a function pointer will do.

    – Davis Herring
    4 hours ago






  • 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
    4 hours ago











  • 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
    4 hours ago







  • 1





    @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
    4 hours ago











  • 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 ifs...

    – Aconcagua
    3 hours ago















7















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?










share|improve this question







New contributor




Alireza Shafaei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.















  • 5





    If you’re interested in performance, don’t use std::function when a function pointer will do.

    – Davis Herring
    4 hours ago






  • 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
    4 hours ago











  • 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
    4 hours ago







  • 1





    @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
    4 hours ago











  • 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 ifs...

    – Aconcagua
    3 hours ago













7












7








7








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?










share|improve this question







New contributor




Alireza Shafaei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.












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++






share|improve this question







New contributor




Alireza Shafaei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question







New contributor




Alireza Shafaei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question






New contributor




Alireza Shafaei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked 4 hours ago









Alireza ShafaeiAlireza Shafaei

361




361




New contributor




Alireza Shafaei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





Alireza Shafaei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






Alireza Shafaei is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







  • 5





    If you’re interested in performance, don’t use std::function when a function pointer will do.

    – Davis Herring
    4 hours ago






  • 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
    4 hours ago











  • 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
    4 hours ago







  • 1





    @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
    4 hours ago











  • 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 ifs...

    – Aconcagua
    3 hours ago












  • 5





    If you’re interested in performance, don’t use std::function when a function pointer will do.

    – Davis Herring
    4 hours ago






  • 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
    4 hours ago











  • 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
    4 hours ago







  • 1





    @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
    4 hours ago











  • 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 ifs...

    – Aconcagua
    3 hours ago







5




5





If you’re interested in performance, don’t use std::function when a function pointer will do.

– Davis Herring
4 hours ago





If you’re interested in performance, don’t use std::function when a function pointer will do.

– Davis Herring
4 hours ago




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
4 hours ago





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
4 hours ago













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
4 hours ago






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
4 hours ago





1




1





@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
4 hours ago





@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
4 hours ago













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 ifs...

– Aconcagua
3 hours ago





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 ifs...

– Aconcagua
3 hours ago












2 Answers
2






active

oldest

votes


















8














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 bools 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 bools 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 bools 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();






share|improve this answer

























  • 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
    3 hours ago












  • 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
    3 hours ago












  • The lookup table is a runtime solution. You can get the right function just by indexing into it

    – Jorge Perez
    3 hours ago











  • I added code showing exactly how to do that

    – Jorge Perez
    3 hours 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 proposed switch statement...

    – Aconcagua
    3 hours ago



















0














Short of JIT compilation, you can’t do better than your 2^n functions, although you can of course use a template to avoid writing them all out. You still need a (massive) if-else tree to dispatch to the correct implementation, so the source (not just the binary) still scales exponentially with the number of variables.






share|improve this answer























  • If you know something at compiletime, it's easy to template it. Especially in the OP's case.

    – Jorge Perez
    4 hours ago











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.









draft saved

draft discarded


















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

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









8














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 bools 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 bools 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 bools 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();






share|improve this answer

























  • 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
    3 hours ago












  • 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
    3 hours ago












  • The lookup table is a runtime solution. You can get the right function just by indexing into it

    – Jorge Perez
    3 hours ago











  • I added code showing exactly how to do that

    – Jorge Perez
    3 hours 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 proposed switch statement...

    – Aconcagua
    3 hours ago
















8














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 bools 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 bools 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 bools 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();






share|improve this answer

























  • 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
    3 hours ago












  • 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
    3 hours ago












  • The lookup table is a runtime solution. You can get the right function just by indexing into it

    – Jorge Perez
    3 hours ago











  • I added code showing exactly how to do that

    – Jorge Perez
    3 hours 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 proposed switch statement...

    – Aconcagua
    3 hours ago














8












8








8







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 bools 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 bools 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 bools 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();






share|improve this answer















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 bools 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 bools 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 bools 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();







share|improve this answer














share|improve this answer



share|improve this answer








edited 2 hours ago

























answered 4 hours ago









Jorge PerezJorge Perez

1,042414




1,042414












  • 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
    3 hours ago












  • 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
    3 hours ago












  • The lookup table is a runtime solution. You can get the right function just by indexing into it

    – Jorge Perez
    3 hours ago











  • I added code showing exactly how to do that

    – Jorge Perez
    3 hours 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 proposed switch statement...

    – Aconcagua
    3 hours 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
    3 hours ago












  • 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
    3 hours ago












  • The lookup table is a runtime solution. You can get the right function just by indexing into it

    – Jorge Perez
    3 hours ago











  • I added code showing exactly how to do that

    – Jorge Perez
    3 hours 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 proposed switch statement...

    – Aconcagua
    3 hours 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
3 hours 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
3 hours ago














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
3 hours ago






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
3 hours ago














The lookup table is a runtime solution. You can get the right function just by indexing into it

– Jorge Perez
3 hours ago





The lookup table is a runtime solution. You can get the right function just by indexing into it

– Jorge Perez
3 hours ago













I added code showing exactly how to do that

– Jorge Perez
3 hours ago





I added code showing exactly how to do that

– Jorge Perez
3 hours 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
3 hours 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
3 hours ago














0














Short of JIT compilation, you can’t do better than your 2^n functions, although you can of course use a template to avoid writing them all out. You still need a (massive) if-else tree to dispatch to the correct implementation, so the source (not just the binary) still scales exponentially with the number of variables.






share|improve this answer























  • If you know something at compiletime, it's easy to template it. Especially in the OP's case.

    – Jorge Perez
    4 hours ago















0














Short of JIT compilation, you can’t do better than your 2^n functions, although you can of course use a template to avoid writing them all out. You still need a (massive) if-else tree to dispatch to the correct implementation, so the source (not just the binary) still scales exponentially with the number of variables.






share|improve this answer























  • If you know something at compiletime, it's easy to template it. Especially in the OP's case.

    – Jorge Perez
    4 hours ago













0












0








0







Short of JIT compilation, you can’t do better than your 2^n functions, although you can of course use a template to avoid writing them all out. You still need a (massive) if-else tree to dispatch to the correct implementation, so the source (not just the binary) still scales exponentially with the number of variables.






share|improve this answer













Short of JIT compilation, you can’t do better than your 2^n functions, although you can of course use a template to avoid writing them all out. You still need a (massive) if-else tree to dispatch to the correct implementation, so the source (not just the binary) still scales exponentially with the number of variables.







share|improve this answer












share|improve this answer



share|improve this answer










answered 4 hours ago









Davis HerringDavis Herring

8,8871736




8,8871736












  • If you know something at compiletime, it's easy to template it. Especially in the OP's case.

    – Jorge Perez
    4 hours ago

















  • If you know something at compiletime, it's easy to template it. Especially in the OP's case.

    – Jorge Perez
    4 hours ago
















If you know something at compiletime, it's easy to template it. Especially in the OP's case.

– Jorge Perez
4 hours ago





If you know something at compiletime, it's easy to template it. Especially in the OP's case.

– Jorge Perez
4 hours ago










Alireza Shafaei is a new contributor. Be nice, and check out our Code of Conduct.









draft saved

draft discarded


















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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Андора Зьмест Гісторыя | Палітыка | Адміністрацыйны падзел | Геаграфія | Эканоміка | Дэмаграфія | Крыніцы | Вонкавыя спасылкі | Навігацыйнае мэню"CIA World Factbook entry: Andorra"."Andorra 2008, Departament d'estadística d'Andorra"Андорарр

J. J. Abrams Índice Traxectoria | Filmografía | Premios | Notas | Véxase tamén | Menú de navegacióne"J.J. Abrams: Biography"Arquivado"'Star Trek' sequel on track"Arquivado"J.J. Abrams Producing Samurai Jack Movie"Arquivado"EXCLUSIVE: J.J. Abrams Goes Into Warp Speed with Star Trek and Beyond"Arquivado"David Semel To Direct Jonah Nolan/J.J. Abrams' CBS Pilot 'Person Of Interest'"Arquivado"Fox orders J.J. Abrams pilot 'Alcatraz'"ArquivadoJ. J. AbramsJ. J. AbramsWorldCat81800131p24091041000XX116709414031616ma11226833654496ID052246713376222X511412nm00091900000 0001 1772 5428no98124254ID0000002883100650044xx0054597000141374297344064w64f2mjx14255303415344

Сэнт-Люіс Вонкавыя спасылкі | Навігацыйнае мэню38°37′38″ пн. ш. 90°11′52″ з. д. / 38.62722° пн. ш. 90.19778° з. д. / 38.62722; -90.1977838°37′38″ пн. ш. 90°11′52″ з. д. / 38.62722° пн. ш. 90.19778° з. д. / 38.62722; -90.19778stlouis-mo.govСэнт-ЛюісAnnual Estimates of the Resident Population for Incorporated Places – U.S. Census Bureau, Population Division