Enforcing function contract at compile time when possible












13















(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)



Let's say, we have a single-argument foo, semantically defined as



int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}

return *parg;
}


The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.



Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.



Here are some potential routes which do not solve the problem:




  • Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments

  • Making function a constexpr - this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc inserts ud2 instruction, which is not what I want.










share|improve this question




















  • 6





    out of curiosity, why this Q is upvoted while linked-one is downvoted?

    – apple apple
    Dec 26 '18 at 15:11






  • 1





    @appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.

    – YSC
    Dec 26 '18 at 15:14






  • 6





    @YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.

    – apple apple
    Dec 26 '18 at 15:22






  • 1





    @appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).

    – YSC
    Dec 26 '18 at 15:27






  • 3





    @IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.

    – SergeyA
    Dec 26 '18 at 15:39
















13















(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)



Let's say, we have a single-argument foo, semantically defined as



int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}

return *parg;
}


The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.



Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.



Here are some potential routes which do not solve the problem:




  • Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments

  • Making function a constexpr - this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc inserts ud2 instruction, which is not what I want.










share|improve this question




















  • 6





    out of curiosity, why this Q is upvoted while linked-one is downvoted?

    – apple apple
    Dec 26 '18 at 15:11






  • 1





    @appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.

    – YSC
    Dec 26 '18 at 15:14






  • 6





    @YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.

    – apple apple
    Dec 26 '18 at 15:22






  • 1





    @appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).

    – YSC
    Dec 26 '18 at 15:27






  • 3





    @IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.

    – SergeyA
    Dec 26 '18 at 15:39














13












13








13


8






(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)



Let's say, we have a single-argument foo, semantically defined as



int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}

return *parg;
}


The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.



Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.



Here are some potential routes which do not solve the problem:




  • Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments

  • Making function a constexpr - this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc inserts ud2 instruction, which is not what I want.










share|improve this question
















(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)



Let's say, we have a single-argument foo, semantically defined as



int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}

return *parg;
}


The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.



Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.



Here are some potential routes which do not solve the problem:




  • Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments

  • Making function a constexpr - this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc inserts ud2 instruction, which is not what I want.







c++






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 26 '18 at 15:44







SergeyA

















asked Dec 26 '18 at 14:53









SergeyASergeyA

41.6k53783




41.6k53783








  • 6





    out of curiosity, why this Q is upvoted while linked-one is downvoted?

    – apple apple
    Dec 26 '18 at 15:11






  • 1





    @appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.

    – YSC
    Dec 26 '18 at 15:14






  • 6





    @YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.

    – apple apple
    Dec 26 '18 at 15:22






  • 1





    @appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).

    – YSC
    Dec 26 '18 at 15:27






  • 3





    @IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.

    – SergeyA
    Dec 26 '18 at 15:39














  • 6





    out of curiosity, why this Q is upvoted while linked-one is downvoted?

    – apple apple
    Dec 26 '18 at 15:11






  • 1





    @appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.

    – YSC
    Dec 26 '18 at 15:14






  • 6





    @YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.

    – apple apple
    Dec 26 '18 at 15:22






  • 1





    @appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).

    – YSC
    Dec 26 '18 at 15:27






  • 3





    @IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.

    – SergeyA
    Dec 26 '18 at 15:39








6




6





out of curiosity, why this Q is upvoted while linked-one is downvoted?

– apple apple
Dec 26 '18 at 15:11





out of curiosity, why this Q is upvoted while linked-one is downvoted?

– apple apple
Dec 26 '18 at 15:11




1




1





@appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.

– YSC
Dec 26 '18 at 15:14





@appleapple Because this one is #1 well-formulated, #2 gives a short a suffisant context and #3 defines a precise (SMART) objective.

– YSC
Dec 26 '18 at 15:14




6




6





@YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.

– apple apple
Dec 26 '18 at 15:22





@YSC well, this question does not show any research effort; it's unclear or not useful. I'd give a downvote if I have to cast one.

– apple apple
Dec 26 '18 at 15:22




1




1





@appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).

– YSC
Dec 26 '18 at 15:27





@appleapple You don't have to cast one, but if you want to, feel free to do so. This is a matter of taste I guess. I find it useful (I never succeded at that task and I think it would be nice to have an API making a value-related contract enforced by a compiler error).

– YSC
Dec 26 '18 at 15:27




3




3





@IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.

– SergeyA
Dec 26 '18 at 15:39





@IłyaBursov - not a duplicate, suggested answer doesn't solve the problem.

– SergeyA
Dec 26 '18 at 15:39












3 Answers
3






active

oldest

votes


















4














I got error with constexpr when used in constant expression for:



constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}


Demo



We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant



// alias to shorten name. 
template <int N>
using int_c = std::integral_constant<int, N>;


Possibly with UDL with operator "" _c to have 5_c, 42_c.



and then, add overload with that:



template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}


So:



foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile

// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile


As I said, arguments are not known to be constant inside the function, and is_constexpr seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p), so with MACRO, we can do the dispatch:



#define FOO(X) [&](){ 
if constexpr (__builtin_constant_p(X)) {
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
} else {
return foo(X);
}
}()


Demo



Note: Cannot use foo(int_c<X>{}) directly, even in if constexpr, as there is still some syntax check.






share|improve this answer


























  • Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.

    – SergeyA
    Dec 26 '18 at 20:17













  • I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided

    – SergeyA
    Dec 26 '18 at 20:24













  • That's why I provide in my answer way to pass compile time argument (with int_c) which allows to check at compile time , as they call it in constant expression.

    – Jarod42
    Dec 26 '18 at 20:26













  • Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.

    – SergeyA
    Dec 26 '18 at 20:34











  • Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )

    – Jarod42
    Dec 26 '18 at 22:07



















2














gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:



template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}

return *parg;
}

#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)


these statements produce compile time error:




  • foo(5)

  • foo(2+3)

  • constexpr int i = 5; foo(i);


while all others - runtime segfault (or ub if no nullptr is used)






share|improve this answer































    0














    It's not perfect and it requires us to use arguments in two different places, but it 'works':



    template<int N = 0>
    int foo(int arg = 0) {
    static_assert(N != 5, "N cannot be 5!");
    int* parg;
    if (arg != 5) {
    parg = &arg;
    }

    return *parg;
    }


    We can call it like so:



    foo<5>();   // does not compile
    foo(5); // UB
    foo<5>(5); // does not compile
    foo<5>(10); // does not compile
    foo<10>(5); // UB
    foo(); // fine
    foo<10>(); // fine
    foo(10); // fine





    share|improve this answer



















    • 2





      No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.

      – SergeyA
      Dec 26 '18 at 15:53






    • 1





      Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>

      – Fureeish
      Dec 26 '18 at 15:54











    • You might add an additional runtime check that argument are equal or defaulted.

      – Jarod42
      Dec 26 '18 at 22:12











    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
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53933634%2fenforcing-function-contract-at-compile-time-when-possible%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









    4














    I got error with constexpr when used in constant expression for:



    constexpr int foo(int arg) {
    int* parg = nullptr;
    if (arg != 5) {
    parg = &arg;
    }
    return *parg;
    }


    Demo



    We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant



    // alias to shorten name. 
    template <int N>
    using int_c = std::integral_constant<int, N>;


    Possibly with UDL with operator "" _c to have 5_c, 42_c.



    and then, add overload with that:



    template <int N>
    constexpr auto foo(int_c<N>) {
    return int_c<foo(N)>{};
    }


    So:



    foo(int_c<42>{}); // OK
    foo(int_c<5>{}); // Fail to compile

    // and with previous constexpr:
    foo(5); // Runtime error, No compile time diagnostic
    constexpr auto r = foo(5); // Fail to compile


    As I said, arguments are not known to be constant inside the function, and is_constexpr seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p), so with MACRO, we can do the dispatch:



    #define FOO(X) [&](){ 
    if constexpr (__builtin_constant_p(X)) {
    return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
    } else {
    return foo(X);
    }
    }()


    Demo



    Note: Cannot use foo(int_c<X>{}) directly, even in if constexpr, as there is still some syntax check.






    share|improve this answer


























    • Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.

      – SergeyA
      Dec 26 '18 at 20:17













    • I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided

      – SergeyA
      Dec 26 '18 at 20:24













    • That's why I provide in my answer way to pass compile time argument (with int_c) which allows to check at compile time , as they call it in constant expression.

      – Jarod42
      Dec 26 '18 at 20:26













    • Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.

      – SergeyA
      Dec 26 '18 at 20:34











    • Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )

      – Jarod42
      Dec 26 '18 at 22:07
















    4














    I got error with constexpr when used in constant expression for:



    constexpr int foo(int arg) {
    int* parg = nullptr;
    if (arg != 5) {
    parg = &arg;
    }
    return *parg;
    }


    Demo



    We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant



    // alias to shorten name. 
    template <int N>
    using int_c = std::integral_constant<int, N>;


    Possibly with UDL with operator "" _c to have 5_c, 42_c.



    and then, add overload with that:



    template <int N>
    constexpr auto foo(int_c<N>) {
    return int_c<foo(N)>{};
    }


    So:



    foo(int_c<42>{}); // OK
    foo(int_c<5>{}); // Fail to compile

    // and with previous constexpr:
    foo(5); // Runtime error, No compile time diagnostic
    constexpr auto r = foo(5); // Fail to compile


    As I said, arguments are not known to be constant inside the function, and is_constexpr seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p), so with MACRO, we can do the dispatch:



    #define FOO(X) [&](){ 
    if constexpr (__builtin_constant_p(X)) {
    return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
    } else {
    return foo(X);
    }
    }()


    Demo



    Note: Cannot use foo(int_c<X>{}) directly, even in if constexpr, as there is still some syntax check.






    share|improve this answer


























    • Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.

      – SergeyA
      Dec 26 '18 at 20:17













    • I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided

      – SergeyA
      Dec 26 '18 at 20:24













    • That's why I provide in my answer way to pass compile time argument (with int_c) which allows to check at compile time , as they call it in constant expression.

      – Jarod42
      Dec 26 '18 at 20:26













    • Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.

      – SergeyA
      Dec 26 '18 at 20:34











    • Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )

      – Jarod42
      Dec 26 '18 at 22:07














    4












    4








    4







    I got error with constexpr when used in constant expression for:



    constexpr int foo(int arg) {
    int* parg = nullptr;
    if (arg != 5) {
    parg = &arg;
    }
    return *parg;
    }


    Demo



    We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant



    // alias to shorten name. 
    template <int N>
    using int_c = std::integral_constant<int, N>;


    Possibly with UDL with operator "" _c to have 5_c, 42_c.



    and then, add overload with that:



    template <int N>
    constexpr auto foo(int_c<N>) {
    return int_c<foo(N)>{};
    }


    So:



    foo(int_c<42>{}); // OK
    foo(int_c<5>{}); // Fail to compile

    // and with previous constexpr:
    foo(5); // Runtime error, No compile time diagnostic
    constexpr auto r = foo(5); // Fail to compile


    As I said, arguments are not known to be constant inside the function, and is_constexpr seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p), so with MACRO, we can do the dispatch:



    #define FOO(X) [&](){ 
    if constexpr (__builtin_constant_p(X)) {
    return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
    } else {
    return foo(X);
    }
    }()


    Demo



    Note: Cannot use foo(int_c<X>{}) directly, even in if constexpr, as there is still some syntax check.






    share|improve this answer















    I got error with constexpr when used in constant expression for:



    constexpr int foo(int arg) {
    int* parg = nullptr;
    if (arg != 5) {
    parg = &arg;
    }
    return *parg;
    }


    Demo



    We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant



    // alias to shorten name. 
    template <int N>
    using int_c = std::integral_constant<int, N>;


    Possibly with UDL with operator "" _c to have 5_c, 42_c.



    and then, add overload with that:



    template <int N>
    constexpr auto foo(int_c<N>) {
    return int_c<foo(N)>{};
    }


    So:



    foo(int_c<42>{}); // OK
    foo(int_c<5>{}); // Fail to compile

    // and with previous constexpr:
    foo(5); // Runtime error, No compile time diagnostic
    constexpr auto r = foo(5); // Fail to compile


    As I said, arguments are not known to be constant inside the function, and is_constexpr seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p), so with MACRO, we can do the dispatch:



    #define FOO(X) [&](){ 
    if constexpr (__builtin_constant_p(X)) {
    return foo(int_c<__builtin_constant_p (X) ? X : 0>{});
    } else {
    return foo(X);
    }
    }()


    Demo



    Note: Cannot use foo(int_c<X>{}) directly, even in if constexpr, as there is still some syntax check.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Dec 27 '18 at 14:20

























    answered Dec 26 '18 at 19:20









    Jarod42Jarod42

    114k12101182




    114k12101182













    • Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.

      – SergeyA
      Dec 26 '18 at 20:17













    • I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided

      – SergeyA
      Dec 26 '18 at 20:24













    • That's why I provide in my answer way to pass compile time argument (with int_c) which allows to check at compile time , as they call it in constant expression.

      – Jarod42
      Dec 26 '18 at 20:26













    • Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.

      – SergeyA
      Dec 26 '18 at 20:34











    • Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )

      – Jarod42
      Dec 26 '18 at 22:07



















    • Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.

      – SergeyA
      Dec 26 '18 at 20:17













    • I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided

      – SergeyA
      Dec 26 '18 at 20:24













    • That's why I provide in my answer way to pass compile time argument (with int_c) which allows to check at compile time , as they call it in constant expression.

      – Jarod42
      Dec 26 '18 at 20:26













    • Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.

      – SergeyA
      Dec 26 '18 at 20:34











    • Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )

      – Jarod42
      Dec 26 '18 at 22:07

















    Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.

    – SergeyA
    Dec 26 '18 at 20:17







    Constexpr version doesn't give me any diagnostic gcc.godbolt.org/z/ZCho3b when it's result is not used to initialize constant expression variable.

    – SergeyA
    Dec 26 '18 at 20:17















    I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided

    – SergeyA
    Dec 26 '18 at 20:24







    I do understand that, and this is exactly what I am referring to - unless the function is called in constant expression, no diagnostics are provided

    – SergeyA
    Dec 26 '18 at 20:24















    That's why I provide in my answer way to pass compile time argument (with int_c) which allows to check at compile time , as they call it in constant expression.

    – Jarod42
    Dec 26 '18 at 20:26







    That's why I provide in my answer way to pass compile time argument (with int_c) which allows to check at compile time , as they call it in constant expression.

    – Jarod42
    Dec 26 '18 at 20:26















    Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.

    – SergeyA
    Dec 26 '18 at 20:34





    Jarod, may be I am not making myself clear enough. The goal is to have a callable function, which would enforce contract in compile time when it possible (i.e. argument is known). Your solution effectively introduces two overloads, and successful compile-time check is predicated on developers discipline to call second overload.

    – SergeyA
    Dec 26 '18 at 20:34













    Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )

    – Jarod42
    Dec 26 '18 at 22:07





    Found a way with built-in of gcc supported by clang (and so works on clang but not with g++ ;-) )

    – Jarod42
    Dec 26 '18 at 22:07













    2














    gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:



    template <int D>
    int foo_ub(int arg) {
    static_assert(D != 5, "error");
    int* parg = nullptr;
    if (arg != 5) {
    parg = &arg;
    }

    return *parg;
    }

    #define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)


    these statements produce compile time error:




    • foo(5)

    • foo(2+3)

    • constexpr int i = 5; foo(i);


    while all others - runtime segfault (or ub if no nullptr is used)






    share|improve this answer




























      2














      gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:



      template <int D>
      int foo_ub(int arg) {
      static_assert(D != 5, "error");
      int* parg = nullptr;
      if (arg != 5) {
      parg = &arg;
      }

      return *parg;
      }

      #define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)


      these statements produce compile time error:




      • foo(5)

      • foo(2+3)

      • constexpr int i = 5; foo(i);


      while all others - runtime segfault (or ub if no nullptr is used)






      share|improve this answer


























        2












        2








        2







        gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:



        template <int D>
        int foo_ub(int arg) {
        static_assert(D != 5, "error");
        int* parg = nullptr;
        if (arg != 5) {
        parg = &arg;
        }

        return *parg;
        }

        #define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)


        these statements produce compile time error:




        • foo(5)

        • foo(2+3)

        • constexpr int i = 5; foo(i);


        while all others - runtime segfault (or ub if no nullptr is used)






        share|improve this answer













        gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:



        template <int D>
        int foo_ub(int arg) {
        static_assert(D != 5, "error");
        int* parg = nullptr;
        if (arg != 5) {
        parg = &arg;
        }

        return *parg;
        }

        #define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)


        these statements produce compile time error:




        • foo(5)

        • foo(2+3)

        • constexpr int i = 5; foo(i);


        while all others - runtime segfault (or ub if no nullptr is used)







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Dec 26 '18 at 23:46









        Iłya BursovIłya Bursov

        18.1k32543




        18.1k32543























            0














            It's not perfect and it requires us to use arguments in two different places, but it 'works':



            template<int N = 0>
            int foo(int arg = 0) {
            static_assert(N != 5, "N cannot be 5!");
            int* parg;
            if (arg != 5) {
            parg = &arg;
            }

            return *parg;
            }


            We can call it like so:



            foo<5>();   // does not compile
            foo(5); // UB
            foo<5>(5); // does not compile
            foo<5>(10); // does not compile
            foo<10>(5); // UB
            foo(); // fine
            foo<10>(); // fine
            foo(10); // fine





            share|improve this answer



















            • 2





              No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.

              – SergeyA
              Dec 26 '18 at 15:53






            • 1





              Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>

              – Fureeish
              Dec 26 '18 at 15:54











            • You might add an additional runtime check that argument are equal or defaulted.

              – Jarod42
              Dec 26 '18 at 22:12
















            0














            It's not perfect and it requires us to use arguments in two different places, but it 'works':



            template<int N = 0>
            int foo(int arg = 0) {
            static_assert(N != 5, "N cannot be 5!");
            int* parg;
            if (arg != 5) {
            parg = &arg;
            }

            return *parg;
            }


            We can call it like so:



            foo<5>();   // does not compile
            foo(5); // UB
            foo<5>(5); // does not compile
            foo<5>(10); // does not compile
            foo<10>(5); // UB
            foo(); // fine
            foo<10>(); // fine
            foo(10); // fine





            share|improve this answer



















            • 2





              No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.

              – SergeyA
              Dec 26 '18 at 15:53






            • 1





              Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>

              – Fureeish
              Dec 26 '18 at 15:54











            • You might add an additional runtime check that argument are equal or defaulted.

              – Jarod42
              Dec 26 '18 at 22:12














            0












            0








            0







            It's not perfect and it requires us to use arguments in two different places, but it 'works':



            template<int N = 0>
            int foo(int arg = 0) {
            static_assert(N != 5, "N cannot be 5!");
            int* parg;
            if (arg != 5) {
            parg = &arg;
            }

            return *parg;
            }


            We can call it like so:



            foo<5>();   // does not compile
            foo(5); // UB
            foo<5>(5); // does not compile
            foo<5>(10); // does not compile
            foo<10>(5); // UB
            foo(); // fine
            foo<10>(); // fine
            foo(10); // fine





            share|improve this answer













            It's not perfect and it requires us to use arguments in two different places, but it 'works':



            template<int N = 0>
            int foo(int arg = 0) {
            static_assert(N != 5, "N cannot be 5!");
            int* parg;
            if (arg != 5) {
            parg = &arg;
            }

            return *parg;
            }


            We can call it like so:



            foo<5>();   // does not compile
            foo(5); // UB
            foo<5>(5); // does not compile
            foo<5>(10); // does not compile
            foo<10>(5); // UB
            foo(); // fine
            foo<10>(); // fine
            foo(10); // fine






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Dec 26 '18 at 15:50









            FureeishFureeish

            3,17421028




            3,17421028








            • 2





              No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.

              – SergeyA
              Dec 26 '18 at 15:53






            • 1





              Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>

              – Fureeish
              Dec 26 '18 at 15:54











            • You might add an additional runtime check that argument are equal or defaulted.

              – Jarod42
              Dec 26 '18 at 22:12














            • 2





              No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.

              – SergeyA
              Dec 26 '18 at 15:53






            • 1





              Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>

              – Fureeish
              Dec 26 '18 at 15:54











            • You might add an additional runtime check that argument are equal or defaulted.

              – Jarod42
              Dec 26 '18 at 22:12








            2




            2





            No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.

            – SergeyA
            Dec 26 '18 at 15:53





            No, it doesn't work. Behavior is dependent on programmer's discipline (making sure to provide template argument when it's known at compile time). Instead of this approach, if programmer is disciplined, I'd simply have two functions - templated and not.

            – SergeyA
            Dec 26 '18 at 15:53




            1




            1





            Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>

            – Fureeish
            Dec 26 '18 at 15:54





            Fair, thank you for the comment. I totally agree that this does not actually solve the entire problem, but I will leave it as a neutral hint / information for future visitors :>

            – Fureeish
            Dec 26 '18 at 15:54













            You might add an additional runtime check that argument are equal or defaulted.

            – Jarod42
            Dec 26 '18 at 22:12





            You might add an additional runtime check that argument are equal or defaulted.

            – Jarod42
            Dec 26 '18 at 22:12


















            draft saved

            draft discarded




















































            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%2f53933634%2fenforcing-function-contract-at-compile-time-when-possible%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

            Ellipse (mathématiques)

            Quarter-circle Tiles

            Mont Emei