SFINAE for function body












3















I often use SFINAE to remove a function from the overload set if the function body does not make sense(i.e. does not compile). Would it be possible to add to C++ a simple require statement?



For example, let's have a function:



template <typename T>
T twice(T t) {
return 2 * t;
}


Then I get:



twice(1.0);
twice("hello"); // Error: invalid operands of types ‘int’ and ‘const char*’ to binary ‘operator*’


I want to get an error that says that there is not function twice for argument of type const char *



I would love to write something like:



template <typename T>
requires function_body_compiles
T twice(T t) {
return 2 * t;
}


Then I would get



twice(1.0);
twice("hello"); // Error: no matching function for call to ‘twice2(const char [6])’




More motivation: I was watching the talk The Nightmare of Move Semantics for Trivial Classes and his final SFINAE is basically saying: use this constructor when it does compile. For a more complicated constructor writing the correct SFINAE would be a nightmare.



Do you think that adding requires function_body_compiles to c++ would make sense? Or is there a fundamental problem I'm missing? How badly could this be abused or misused?










share|improve this question























  • It would make SFINAE requirements for T unclear. One would have to examine the entire constructor body to determine if a particular T fits or not.

    – HolyBlackCat
    Nov 23 '18 at 6:50






  • 3





    Such a template could not be forward-declared. And it would permit misspellings or other simple typos to go undetected: Suppose the function body calls printf but you forgot to #include <stdio.h>. Suddenly, the entire overload vanishes! And what would this be: template<typename T> requires function_body_compiles T once(T t) { return rand() ? once(t) : t; }? The function body compiles if and only if the function body compiles.

    – Raymond Chen
    Nov 23 '18 at 7:07











  • @RaymondChen The forward-declaration is definitely a very valid point and yes the circular dependency is definitely a problem, but you can achieve this even now. Actually, Nicolai talks about it at that CppCon talk around 38:50. Although, I see your point with typos, but I think that it could be detected quite easily. You try to call a function, and the compiler will tell you that there is no such a function because the one you actually want to call was removed due to the typo. The only problem would be if there is another function overload match, does it happen often?

    – tom
    Nov 23 '18 at 7:42











  • Isn't this what concepts are all about? (and not contracts)

    – Matthieu Brucher
    Nov 23 '18 at 8:21








  • 1





    @Francis Cugler Just require a negation of a predicate e.g. require !std::is_same_v<T, int>. Of course, you can introduce a predicate or a concept with a better name but there is definitely no need for a new keyword.

    – tom
    Nov 27 '18 at 5:43
















3















I often use SFINAE to remove a function from the overload set if the function body does not make sense(i.e. does not compile). Would it be possible to add to C++ a simple require statement?



For example, let's have a function:



template <typename T>
T twice(T t) {
return 2 * t;
}


Then I get:



twice(1.0);
twice("hello"); // Error: invalid operands of types ‘int’ and ‘const char*’ to binary ‘operator*’


I want to get an error that says that there is not function twice for argument of type const char *



I would love to write something like:



template <typename T>
requires function_body_compiles
T twice(T t) {
return 2 * t;
}


Then I would get



twice(1.0);
twice("hello"); // Error: no matching function for call to ‘twice2(const char [6])’




More motivation: I was watching the talk The Nightmare of Move Semantics for Trivial Classes and his final SFINAE is basically saying: use this constructor when it does compile. For a more complicated constructor writing the correct SFINAE would be a nightmare.



Do you think that adding requires function_body_compiles to c++ would make sense? Or is there a fundamental problem I'm missing? How badly could this be abused or misused?










share|improve this question























  • It would make SFINAE requirements for T unclear. One would have to examine the entire constructor body to determine if a particular T fits or not.

    – HolyBlackCat
    Nov 23 '18 at 6:50






  • 3





    Such a template could not be forward-declared. And it would permit misspellings or other simple typos to go undetected: Suppose the function body calls printf but you forgot to #include <stdio.h>. Suddenly, the entire overload vanishes! And what would this be: template<typename T> requires function_body_compiles T once(T t) { return rand() ? once(t) : t; }? The function body compiles if and only if the function body compiles.

    – Raymond Chen
    Nov 23 '18 at 7:07











  • @RaymondChen The forward-declaration is definitely a very valid point and yes the circular dependency is definitely a problem, but you can achieve this even now. Actually, Nicolai talks about it at that CppCon talk around 38:50. Although, I see your point with typos, but I think that it could be detected quite easily. You try to call a function, and the compiler will tell you that there is no such a function because the one you actually want to call was removed due to the typo. The only problem would be if there is another function overload match, does it happen often?

    – tom
    Nov 23 '18 at 7:42











  • Isn't this what concepts are all about? (and not contracts)

    – Matthieu Brucher
    Nov 23 '18 at 8:21








  • 1





    @Francis Cugler Just require a negation of a predicate e.g. require !std::is_same_v<T, int>. Of course, you can introduce a predicate or a concept with a better name but there is definitely no need for a new keyword.

    – tom
    Nov 27 '18 at 5:43














3












3








3








I often use SFINAE to remove a function from the overload set if the function body does not make sense(i.e. does not compile). Would it be possible to add to C++ a simple require statement?



For example, let's have a function:



template <typename T>
T twice(T t) {
return 2 * t;
}


Then I get:



twice(1.0);
twice("hello"); // Error: invalid operands of types ‘int’ and ‘const char*’ to binary ‘operator*’


I want to get an error that says that there is not function twice for argument of type const char *



I would love to write something like:



template <typename T>
requires function_body_compiles
T twice(T t) {
return 2 * t;
}


Then I would get



twice(1.0);
twice("hello"); // Error: no matching function for call to ‘twice2(const char [6])’




More motivation: I was watching the talk The Nightmare of Move Semantics for Trivial Classes and his final SFINAE is basically saying: use this constructor when it does compile. For a more complicated constructor writing the correct SFINAE would be a nightmare.



Do you think that adding requires function_body_compiles to c++ would make sense? Or is there a fundamental problem I'm missing? How badly could this be abused or misused?










share|improve this question














I often use SFINAE to remove a function from the overload set if the function body does not make sense(i.e. does not compile). Would it be possible to add to C++ a simple require statement?



For example, let's have a function:



template <typename T>
T twice(T t) {
return 2 * t;
}


Then I get:



twice(1.0);
twice("hello"); // Error: invalid operands of types ‘int’ and ‘const char*’ to binary ‘operator*’


I want to get an error that says that there is not function twice for argument of type const char *



I would love to write something like:



template <typename T>
requires function_body_compiles
T twice(T t) {
return 2 * t;
}


Then I would get



twice(1.0);
twice("hello"); // Error: no matching function for call to ‘twice2(const char [6])’




More motivation: I was watching the talk The Nightmare of Move Semantics for Trivial Classes and his final SFINAE is basically saying: use this constructor when it does compile. For a more complicated constructor writing the correct SFINAE would be a nightmare.



Do you think that adding requires function_body_compiles to c++ would make sense? Or is there a fundamental problem I'm missing? How badly could this be abused or misused?







c++ templates c++20






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 23 '18 at 6:47









tomtom

5641622




5641622













  • It would make SFINAE requirements for T unclear. One would have to examine the entire constructor body to determine if a particular T fits or not.

    – HolyBlackCat
    Nov 23 '18 at 6:50






  • 3





    Such a template could not be forward-declared. And it would permit misspellings or other simple typos to go undetected: Suppose the function body calls printf but you forgot to #include <stdio.h>. Suddenly, the entire overload vanishes! And what would this be: template<typename T> requires function_body_compiles T once(T t) { return rand() ? once(t) : t; }? The function body compiles if and only if the function body compiles.

    – Raymond Chen
    Nov 23 '18 at 7:07











  • @RaymondChen The forward-declaration is definitely a very valid point and yes the circular dependency is definitely a problem, but you can achieve this even now. Actually, Nicolai talks about it at that CppCon talk around 38:50. Although, I see your point with typos, but I think that it could be detected quite easily. You try to call a function, and the compiler will tell you that there is no such a function because the one you actually want to call was removed due to the typo. The only problem would be if there is another function overload match, does it happen often?

    – tom
    Nov 23 '18 at 7:42











  • Isn't this what concepts are all about? (and not contracts)

    – Matthieu Brucher
    Nov 23 '18 at 8:21








  • 1





    @Francis Cugler Just require a negation of a predicate e.g. require !std::is_same_v<T, int>. Of course, you can introduce a predicate or a concept with a better name but there is definitely no need for a new keyword.

    – tom
    Nov 27 '18 at 5:43



















  • It would make SFINAE requirements for T unclear. One would have to examine the entire constructor body to determine if a particular T fits or not.

    – HolyBlackCat
    Nov 23 '18 at 6:50






  • 3





    Such a template could not be forward-declared. And it would permit misspellings or other simple typos to go undetected: Suppose the function body calls printf but you forgot to #include <stdio.h>. Suddenly, the entire overload vanishes! And what would this be: template<typename T> requires function_body_compiles T once(T t) { return rand() ? once(t) : t; }? The function body compiles if and only if the function body compiles.

    – Raymond Chen
    Nov 23 '18 at 7:07











  • @RaymondChen The forward-declaration is definitely a very valid point and yes the circular dependency is definitely a problem, but you can achieve this even now. Actually, Nicolai talks about it at that CppCon talk around 38:50. Although, I see your point with typos, but I think that it could be detected quite easily. You try to call a function, and the compiler will tell you that there is no such a function because the one you actually want to call was removed due to the typo. The only problem would be if there is another function overload match, does it happen often?

    – tom
    Nov 23 '18 at 7:42











  • Isn't this what concepts are all about? (and not contracts)

    – Matthieu Brucher
    Nov 23 '18 at 8:21








  • 1





    @Francis Cugler Just require a negation of a predicate e.g. require !std::is_same_v<T, int>. Of course, you can introduce a predicate or a concept with a better name but there is definitely no need for a new keyword.

    – tom
    Nov 27 '18 at 5:43

















It would make SFINAE requirements for T unclear. One would have to examine the entire constructor body to determine if a particular T fits or not.

– HolyBlackCat
Nov 23 '18 at 6:50





It would make SFINAE requirements for T unclear. One would have to examine the entire constructor body to determine if a particular T fits or not.

– HolyBlackCat
Nov 23 '18 at 6:50




3




3





Such a template could not be forward-declared. And it would permit misspellings or other simple typos to go undetected: Suppose the function body calls printf but you forgot to #include <stdio.h>. Suddenly, the entire overload vanishes! And what would this be: template<typename T> requires function_body_compiles T once(T t) { return rand() ? once(t) : t; }? The function body compiles if and only if the function body compiles.

– Raymond Chen
Nov 23 '18 at 7:07





Such a template could not be forward-declared. And it would permit misspellings or other simple typos to go undetected: Suppose the function body calls printf but you forgot to #include <stdio.h>. Suddenly, the entire overload vanishes! And what would this be: template<typename T> requires function_body_compiles T once(T t) { return rand() ? once(t) : t; }? The function body compiles if and only if the function body compiles.

– Raymond Chen
Nov 23 '18 at 7:07













@RaymondChen The forward-declaration is definitely a very valid point and yes the circular dependency is definitely a problem, but you can achieve this even now. Actually, Nicolai talks about it at that CppCon talk around 38:50. Although, I see your point with typos, but I think that it could be detected quite easily. You try to call a function, and the compiler will tell you that there is no such a function because the one you actually want to call was removed due to the typo. The only problem would be if there is another function overload match, does it happen often?

– tom
Nov 23 '18 at 7:42





@RaymondChen The forward-declaration is definitely a very valid point and yes the circular dependency is definitely a problem, but you can achieve this even now. Actually, Nicolai talks about it at that CppCon talk around 38:50. Although, I see your point with typos, but I think that it could be detected quite easily. You try to call a function, and the compiler will tell you that there is no such a function because the one you actually want to call was removed due to the typo. The only problem would be if there is another function overload match, does it happen often?

– tom
Nov 23 '18 at 7:42













Isn't this what concepts are all about? (and not contracts)

– Matthieu Brucher
Nov 23 '18 at 8:21







Isn't this what concepts are all about? (and not contracts)

– Matthieu Brucher
Nov 23 '18 at 8:21






1




1





@Francis Cugler Just require a negation of a predicate e.g. require !std::is_same_v<T, int>. Of course, you can introduce a predicate or a concept with a better name but there is definitely no need for a new keyword.

– tom
Nov 27 '18 at 5:43





@Francis Cugler Just require a negation of a predicate e.g. require !std::is_same_v<T, int>. Of course, you can introduce a predicate or a concept with a better name but there is definitely no need for a new keyword.

– tom
Nov 27 '18 at 5:43












3 Answers
3






active

oldest

votes


















8














The biggest reason why we don't have this feature is that it is hard.



It is hard, because it requires compilers be able to compile nearly arbitrary C++ code, get errors, then back out cleanly.



Existing C++ compilers where not all designed to do this. In fact, it took MSVC most of a decade to have reasonably compliant decltype SFINAE support.



Doing so for full function bodies would be even harder.





Now, even if it was easy, there are reasons not do do this. It mixes implementation and interface in a pretty horrible way.



Rather than go this way, the C++ committee is moving in a completely different direction.



Concepts are the idea that you can express requirements about types in sensible, usually named ways. They are coming in c++20.



As another answer mentions,



template <typename T> requires requires(T t) { { 2 * t } -> T; }
T twice(T t) {
return 2 * t;
}


is a way to do it, but that way is considered bad form. Instead, you should write a concept "can be multiplied by an integer and get the same type back".



template<typename T>
concept IntegerScalable = requires(T t) {
{ 2 * t } -> T;
};


we can then



template <IntegerScalable T>
T twice(T t) {
return 2 * t;
}


and we are done.



A desired next step is called "checked concepts". In checked concepts, the concept it converted into a set of compile-time interfaces for your type T.



Then the body of the function is checked to ensure nothing is done to anything of type T that isn't a requirement of a concept.



Using a theoretical future checked concept,



template <IntegerScalable T>
T twice(T t) {
T n = 7;
if (n > t) return n;
return 2 * t;
}


this would be rejected by the compiler when compiling the template even before a call to the template was done, because the concept IntegerScalable didn't guarantee that you could either initialize a T with an integer, nor that you could compare one T to another with >. Plus I think the above requires move-construction.





There is a hack you can do today.



#define RETURNS(...) 
noexcept(noexcept(__VA_ARGS__))
decltype(__VA_ARGS__)
{ return __VA_ARGS__; }


then your code can be written as:



template<class T>
T twice(T t)
RETURNS( 2 * t )


and you'll get a SFINAE friendly version of twice. It will also be as noexcept as it can be.



A variant of this using => to replace RETURNS and some other stuff was proposed by @Barry, but it has been a year since I've seen it move.



Meanwhile, RETURNS does most of the heavy lifting.






share|improve this answer































    2














    There was a [proposal] filed by Barry Revzin for exactly what you are asking, but in context of lambda expressions. As it requires constructing lambda the syntax would be a bit different:



    auto twice = (auto t) => 2 * t; //sfinae friendly


    or even:



    auto twice = 2 * $0;


    Nevertheless the status of this proposal is still uncertain. You can check it [here].



    However in case of constructor I'm not sure if there would be a way to apply such a construct even if the proposal get accepted. Nevertheless if someone saw the need in case of lambda expressions there is probably potential for language development in the general case.






    share|improve this answer


























    • This is nice, but for complicated functions you do not want to write a lambda.

      – tom
      Nov 23 '18 at 8:45











    • @tom exactly, now I don't see the possibility of what you want in the current standard wording, but when the committee finally accept the Barry's proposal I think the door would get wide open to apply some more interesting from your point of view language improvements...

      – W.F.
      Nov 23 '18 at 8:48













    • Hmm, when I think about it a bit more. This works only for a single line lambda, right? Then it is not as useful as I initially thought. If it is a single line you can as well write it in the trailing return type again and get the desired behavior. It is a bit verbose, but doable.

      – tom
      Nov 23 '18 at 9:53











    • @tom yup, but the expression still can be complex and extensive and duplicating it might be painful... This was the original cause behind the proposal I guess. When you think of it - your desirable behaviour would extend of the requirements to the level of entire block of code.

      – W.F.
      Nov 23 '18 at 10:27













    • @tom Once again I'd like to state that mentioning abbreviated lambda here is rather to point you to the direction of proposing new feature to the language as none of currently available nor the proposal I know of would suit your desired syntax.

      – W.F.
      Nov 23 '18 at 10:31





















    2














    You can do to some extent what you want with requires-expressions (https://godbolt.org/z/6FDT45):



    template <typename T> requires requires(T t) { { 2 * t } -> T; }
    T twice(T t) {
    return 2 * t;
    }

    int main()
    {
    twice(1.0);
    twice("hello"); // Error: Constraints not satisfied
    }


    As you noted in the comments, a helper function cannot be used to avoid writting the function body twice, because
    errors in the implementation are not found until instantiation time. However, requires expressions benefit from
    advantages over decltype(expr) trailing return types:




    • They are not limited to return types.

    • There can be as many expressions as needed.


    What you would like to have is referred to as "concept definition checking". Bjarne Stroustrup discusses why it is
    missing in the concepts design in the paper P0557R0
    (Section 8.2).






    share|improve this answer


























    • I do not need require for that, I can as easily do auto twice(T t) -> decltype(2*t) {...}. The problem is that you have to write the function body twice! This does not scale to more complicated functions.

      – tom
      Nov 23 '18 at 8:37











    • @tom Well. You can write a helper function, maybe in a detail namespace, and invoke it in a requires expression.

      – metalfox
      Nov 23 '18 at 8:41






    • 1





      @tom. It does work. Here's a link for you to try.

      – metalfox
      Nov 23 '18 at 8:48






    • 1





      Nope it does not work. It does not remove the function from the overload set. To test that, I define the twice function without the require, if the require is not satisfied then the unconstrained version should be called. However, calling twice("hello") gives a compiler error instead of calling the unconstrained version. Have a look: godbolt.org/z/LvMXQi

      – tom
      Nov 23 '18 at 9:13






    • 1





      @tom Right. Take a look to my edit ;-)

      – metalfox
      Nov 23 '18 at 9:35











    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%2f53441832%2fsfinae-for-function-body%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









    8














    The biggest reason why we don't have this feature is that it is hard.



    It is hard, because it requires compilers be able to compile nearly arbitrary C++ code, get errors, then back out cleanly.



    Existing C++ compilers where not all designed to do this. In fact, it took MSVC most of a decade to have reasonably compliant decltype SFINAE support.



    Doing so for full function bodies would be even harder.





    Now, even if it was easy, there are reasons not do do this. It mixes implementation and interface in a pretty horrible way.



    Rather than go this way, the C++ committee is moving in a completely different direction.



    Concepts are the idea that you can express requirements about types in sensible, usually named ways. They are coming in c++20.



    As another answer mentions,



    template <typename T> requires requires(T t) { { 2 * t } -> T; }
    T twice(T t) {
    return 2 * t;
    }


    is a way to do it, but that way is considered bad form. Instead, you should write a concept "can be multiplied by an integer and get the same type back".



    template<typename T>
    concept IntegerScalable = requires(T t) {
    { 2 * t } -> T;
    };


    we can then



    template <IntegerScalable T>
    T twice(T t) {
    return 2 * t;
    }


    and we are done.



    A desired next step is called "checked concepts". In checked concepts, the concept it converted into a set of compile-time interfaces for your type T.



    Then the body of the function is checked to ensure nothing is done to anything of type T that isn't a requirement of a concept.



    Using a theoretical future checked concept,



    template <IntegerScalable T>
    T twice(T t) {
    T n = 7;
    if (n > t) return n;
    return 2 * t;
    }


    this would be rejected by the compiler when compiling the template even before a call to the template was done, because the concept IntegerScalable didn't guarantee that you could either initialize a T with an integer, nor that you could compare one T to another with >. Plus I think the above requires move-construction.





    There is a hack you can do today.



    #define RETURNS(...) 
    noexcept(noexcept(__VA_ARGS__))
    decltype(__VA_ARGS__)
    { return __VA_ARGS__; }


    then your code can be written as:



    template<class T>
    T twice(T t)
    RETURNS( 2 * t )


    and you'll get a SFINAE friendly version of twice. It will also be as noexcept as it can be.



    A variant of this using => to replace RETURNS and some other stuff was proposed by @Barry, but it has been a year since I've seen it move.



    Meanwhile, RETURNS does most of the heavy lifting.






    share|improve this answer




























      8














      The biggest reason why we don't have this feature is that it is hard.



      It is hard, because it requires compilers be able to compile nearly arbitrary C++ code, get errors, then back out cleanly.



      Existing C++ compilers where not all designed to do this. In fact, it took MSVC most of a decade to have reasonably compliant decltype SFINAE support.



      Doing so for full function bodies would be even harder.





      Now, even if it was easy, there are reasons not do do this. It mixes implementation and interface in a pretty horrible way.



      Rather than go this way, the C++ committee is moving in a completely different direction.



      Concepts are the idea that you can express requirements about types in sensible, usually named ways. They are coming in c++20.



      As another answer mentions,



      template <typename T> requires requires(T t) { { 2 * t } -> T; }
      T twice(T t) {
      return 2 * t;
      }


      is a way to do it, but that way is considered bad form. Instead, you should write a concept "can be multiplied by an integer and get the same type back".



      template<typename T>
      concept IntegerScalable = requires(T t) {
      { 2 * t } -> T;
      };


      we can then



      template <IntegerScalable T>
      T twice(T t) {
      return 2 * t;
      }


      and we are done.



      A desired next step is called "checked concepts". In checked concepts, the concept it converted into a set of compile-time interfaces for your type T.



      Then the body of the function is checked to ensure nothing is done to anything of type T that isn't a requirement of a concept.



      Using a theoretical future checked concept,



      template <IntegerScalable T>
      T twice(T t) {
      T n = 7;
      if (n > t) return n;
      return 2 * t;
      }


      this would be rejected by the compiler when compiling the template even before a call to the template was done, because the concept IntegerScalable didn't guarantee that you could either initialize a T with an integer, nor that you could compare one T to another with >. Plus I think the above requires move-construction.





      There is a hack you can do today.



      #define RETURNS(...) 
      noexcept(noexcept(__VA_ARGS__))
      decltype(__VA_ARGS__)
      { return __VA_ARGS__; }


      then your code can be written as:



      template<class T>
      T twice(T t)
      RETURNS( 2 * t )


      and you'll get a SFINAE friendly version of twice. It will also be as noexcept as it can be.



      A variant of this using => to replace RETURNS and some other stuff was proposed by @Barry, but it has been a year since I've seen it move.



      Meanwhile, RETURNS does most of the heavy lifting.






      share|improve this answer


























        8












        8








        8







        The biggest reason why we don't have this feature is that it is hard.



        It is hard, because it requires compilers be able to compile nearly arbitrary C++ code, get errors, then back out cleanly.



        Existing C++ compilers where not all designed to do this. In fact, it took MSVC most of a decade to have reasonably compliant decltype SFINAE support.



        Doing so for full function bodies would be even harder.





        Now, even if it was easy, there are reasons not do do this. It mixes implementation and interface in a pretty horrible way.



        Rather than go this way, the C++ committee is moving in a completely different direction.



        Concepts are the idea that you can express requirements about types in sensible, usually named ways. They are coming in c++20.



        As another answer mentions,



        template <typename T> requires requires(T t) { { 2 * t } -> T; }
        T twice(T t) {
        return 2 * t;
        }


        is a way to do it, but that way is considered bad form. Instead, you should write a concept "can be multiplied by an integer and get the same type back".



        template<typename T>
        concept IntegerScalable = requires(T t) {
        { 2 * t } -> T;
        };


        we can then



        template <IntegerScalable T>
        T twice(T t) {
        return 2 * t;
        }


        and we are done.



        A desired next step is called "checked concepts". In checked concepts, the concept it converted into a set of compile-time interfaces for your type T.



        Then the body of the function is checked to ensure nothing is done to anything of type T that isn't a requirement of a concept.



        Using a theoretical future checked concept,



        template <IntegerScalable T>
        T twice(T t) {
        T n = 7;
        if (n > t) return n;
        return 2 * t;
        }


        this would be rejected by the compiler when compiling the template even before a call to the template was done, because the concept IntegerScalable didn't guarantee that you could either initialize a T with an integer, nor that you could compare one T to another with >. Plus I think the above requires move-construction.





        There is a hack you can do today.



        #define RETURNS(...) 
        noexcept(noexcept(__VA_ARGS__))
        decltype(__VA_ARGS__)
        { return __VA_ARGS__; }


        then your code can be written as:



        template<class T>
        T twice(T t)
        RETURNS( 2 * t )


        and you'll get a SFINAE friendly version of twice. It will also be as noexcept as it can be.



        A variant of this using => to replace RETURNS and some other stuff was proposed by @Barry, but it has been a year since I've seen it move.



        Meanwhile, RETURNS does most of the heavy lifting.






        share|improve this answer













        The biggest reason why we don't have this feature is that it is hard.



        It is hard, because it requires compilers be able to compile nearly arbitrary C++ code, get errors, then back out cleanly.



        Existing C++ compilers where not all designed to do this. In fact, it took MSVC most of a decade to have reasonably compliant decltype SFINAE support.



        Doing so for full function bodies would be even harder.





        Now, even if it was easy, there are reasons not do do this. It mixes implementation and interface in a pretty horrible way.



        Rather than go this way, the C++ committee is moving in a completely different direction.



        Concepts are the idea that you can express requirements about types in sensible, usually named ways. They are coming in c++20.



        As another answer mentions,



        template <typename T> requires requires(T t) { { 2 * t } -> T; }
        T twice(T t) {
        return 2 * t;
        }


        is a way to do it, but that way is considered bad form. Instead, you should write a concept "can be multiplied by an integer and get the same type back".



        template<typename T>
        concept IntegerScalable = requires(T t) {
        { 2 * t } -> T;
        };


        we can then



        template <IntegerScalable T>
        T twice(T t) {
        return 2 * t;
        }


        and we are done.



        A desired next step is called "checked concepts". In checked concepts, the concept it converted into a set of compile-time interfaces for your type T.



        Then the body of the function is checked to ensure nothing is done to anything of type T that isn't a requirement of a concept.



        Using a theoretical future checked concept,



        template <IntegerScalable T>
        T twice(T t) {
        T n = 7;
        if (n > t) return n;
        return 2 * t;
        }


        this would be rejected by the compiler when compiling the template even before a call to the template was done, because the concept IntegerScalable didn't guarantee that you could either initialize a T with an integer, nor that you could compare one T to another with >. Plus I think the above requires move-construction.





        There is a hack you can do today.



        #define RETURNS(...) 
        noexcept(noexcept(__VA_ARGS__))
        decltype(__VA_ARGS__)
        { return __VA_ARGS__; }


        then your code can be written as:



        template<class T>
        T twice(T t)
        RETURNS( 2 * t )


        and you'll get a SFINAE friendly version of twice. It will also be as noexcept as it can be.



        A variant of this using => to replace RETURNS and some other stuff was proposed by @Barry, but it has been a year since I've seen it move.



        Meanwhile, RETURNS does most of the heavy lifting.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 23 '18 at 15:59









        Yakk - Adam NevraumontYakk - Adam Nevraumont

        188k21199384




        188k21199384

























            2














            There was a [proposal] filed by Barry Revzin for exactly what you are asking, but in context of lambda expressions. As it requires constructing lambda the syntax would be a bit different:



            auto twice = (auto t) => 2 * t; //sfinae friendly


            or even:



            auto twice = 2 * $0;


            Nevertheless the status of this proposal is still uncertain. You can check it [here].



            However in case of constructor I'm not sure if there would be a way to apply such a construct even if the proposal get accepted. Nevertheless if someone saw the need in case of lambda expressions there is probably potential for language development in the general case.






            share|improve this answer


























            • This is nice, but for complicated functions you do not want to write a lambda.

              – tom
              Nov 23 '18 at 8:45











            • @tom exactly, now I don't see the possibility of what you want in the current standard wording, but when the committee finally accept the Barry's proposal I think the door would get wide open to apply some more interesting from your point of view language improvements...

              – W.F.
              Nov 23 '18 at 8:48













            • Hmm, when I think about it a bit more. This works only for a single line lambda, right? Then it is not as useful as I initially thought. If it is a single line you can as well write it in the trailing return type again and get the desired behavior. It is a bit verbose, but doable.

              – tom
              Nov 23 '18 at 9:53











            • @tom yup, but the expression still can be complex and extensive and duplicating it might be painful... This was the original cause behind the proposal I guess. When you think of it - your desirable behaviour would extend of the requirements to the level of entire block of code.

              – W.F.
              Nov 23 '18 at 10:27













            • @tom Once again I'd like to state that mentioning abbreviated lambda here is rather to point you to the direction of proposing new feature to the language as none of currently available nor the proposal I know of would suit your desired syntax.

              – W.F.
              Nov 23 '18 at 10:31


















            2














            There was a [proposal] filed by Barry Revzin for exactly what you are asking, but in context of lambda expressions. As it requires constructing lambda the syntax would be a bit different:



            auto twice = (auto t) => 2 * t; //sfinae friendly


            or even:



            auto twice = 2 * $0;


            Nevertheless the status of this proposal is still uncertain. You can check it [here].



            However in case of constructor I'm not sure if there would be a way to apply such a construct even if the proposal get accepted. Nevertheless if someone saw the need in case of lambda expressions there is probably potential for language development in the general case.






            share|improve this answer


























            • This is nice, but for complicated functions you do not want to write a lambda.

              – tom
              Nov 23 '18 at 8:45











            • @tom exactly, now I don't see the possibility of what you want in the current standard wording, but when the committee finally accept the Barry's proposal I think the door would get wide open to apply some more interesting from your point of view language improvements...

              – W.F.
              Nov 23 '18 at 8:48













            • Hmm, when I think about it a bit more. This works only for a single line lambda, right? Then it is not as useful as I initially thought. If it is a single line you can as well write it in the trailing return type again and get the desired behavior. It is a bit verbose, but doable.

              – tom
              Nov 23 '18 at 9:53











            • @tom yup, but the expression still can be complex and extensive and duplicating it might be painful... This was the original cause behind the proposal I guess. When you think of it - your desirable behaviour would extend of the requirements to the level of entire block of code.

              – W.F.
              Nov 23 '18 at 10:27













            • @tom Once again I'd like to state that mentioning abbreviated lambda here is rather to point you to the direction of proposing new feature to the language as none of currently available nor the proposal I know of would suit your desired syntax.

              – W.F.
              Nov 23 '18 at 10:31
















            2












            2








            2







            There was a [proposal] filed by Barry Revzin for exactly what you are asking, but in context of lambda expressions. As it requires constructing lambda the syntax would be a bit different:



            auto twice = (auto t) => 2 * t; //sfinae friendly


            or even:



            auto twice = 2 * $0;


            Nevertheless the status of this proposal is still uncertain. You can check it [here].



            However in case of constructor I'm not sure if there would be a way to apply such a construct even if the proposal get accepted. Nevertheless if someone saw the need in case of lambda expressions there is probably potential for language development in the general case.






            share|improve this answer















            There was a [proposal] filed by Barry Revzin for exactly what you are asking, but in context of lambda expressions. As it requires constructing lambda the syntax would be a bit different:



            auto twice = (auto t) => 2 * t; //sfinae friendly


            or even:



            auto twice = 2 * $0;


            Nevertheless the status of this proposal is still uncertain. You can check it [here].



            However in case of constructor I'm not sure if there would be a way to apply such a construct even if the proposal get accepted. Nevertheless if someone saw the need in case of lambda expressions there is probably potential for language development in the general case.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 23 '18 at 8:44

























            answered Nov 23 '18 at 8:06









            W.F.W.F.

            9,81222662




            9,81222662













            • This is nice, but for complicated functions you do not want to write a lambda.

              – tom
              Nov 23 '18 at 8:45











            • @tom exactly, now I don't see the possibility of what you want in the current standard wording, but when the committee finally accept the Barry's proposal I think the door would get wide open to apply some more interesting from your point of view language improvements...

              – W.F.
              Nov 23 '18 at 8:48













            • Hmm, when I think about it a bit more. This works only for a single line lambda, right? Then it is not as useful as I initially thought. If it is a single line you can as well write it in the trailing return type again and get the desired behavior. It is a bit verbose, but doable.

              – tom
              Nov 23 '18 at 9:53











            • @tom yup, but the expression still can be complex and extensive and duplicating it might be painful... This was the original cause behind the proposal I guess. When you think of it - your desirable behaviour would extend of the requirements to the level of entire block of code.

              – W.F.
              Nov 23 '18 at 10:27













            • @tom Once again I'd like to state that mentioning abbreviated lambda here is rather to point you to the direction of proposing new feature to the language as none of currently available nor the proposal I know of would suit your desired syntax.

              – W.F.
              Nov 23 '18 at 10:31





















            • This is nice, but for complicated functions you do not want to write a lambda.

              – tom
              Nov 23 '18 at 8:45











            • @tom exactly, now I don't see the possibility of what you want in the current standard wording, but when the committee finally accept the Barry's proposal I think the door would get wide open to apply some more interesting from your point of view language improvements...

              – W.F.
              Nov 23 '18 at 8:48













            • Hmm, when I think about it a bit more. This works only for a single line lambda, right? Then it is not as useful as I initially thought. If it is a single line you can as well write it in the trailing return type again and get the desired behavior. It is a bit verbose, but doable.

              – tom
              Nov 23 '18 at 9:53











            • @tom yup, but the expression still can be complex and extensive and duplicating it might be painful... This was the original cause behind the proposal I guess. When you think of it - your desirable behaviour would extend of the requirements to the level of entire block of code.

              – W.F.
              Nov 23 '18 at 10:27













            • @tom Once again I'd like to state that mentioning abbreviated lambda here is rather to point you to the direction of proposing new feature to the language as none of currently available nor the proposal I know of would suit your desired syntax.

              – W.F.
              Nov 23 '18 at 10:31



















            This is nice, but for complicated functions you do not want to write a lambda.

            – tom
            Nov 23 '18 at 8:45





            This is nice, but for complicated functions you do not want to write a lambda.

            – tom
            Nov 23 '18 at 8:45













            @tom exactly, now I don't see the possibility of what you want in the current standard wording, but when the committee finally accept the Barry's proposal I think the door would get wide open to apply some more interesting from your point of view language improvements...

            – W.F.
            Nov 23 '18 at 8:48







            @tom exactly, now I don't see the possibility of what you want in the current standard wording, but when the committee finally accept the Barry's proposal I think the door would get wide open to apply some more interesting from your point of view language improvements...

            – W.F.
            Nov 23 '18 at 8:48















            Hmm, when I think about it a bit more. This works only for a single line lambda, right? Then it is not as useful as I initially thought. If it is a single line you can as well write it in the trailing return type again and get the desired behavior. It is a bit verbose, but doable.

            – tom
            Nov 23 '18 at 9:53





            Hmm, when I think about it a bit more. This works only for a single line lambda, right? Then it is not as useful as I initially thought. If it is a single line you can as well write it in the trailing return type again and get the desired behavior. It is a bit verbose, but doable.

            – tom
            Nov 23 '18 at 9:53













            @tom yup, but the expression still can be complex and extensive and duplicating it might be painful... This was the original cause behind the proposal I guess. When you think of it - your desirable behaviour would extend of the requirements to the level of entire block of code.

            – W.F.
            Nov 23 '18 at 10:27







            @tom yup, but the expression still can be complex and extensive and duplicating it might be painful... This was the original cause behind the proposal I guess. When you think of it - your desirable behaviour would extend of the requirements to the level of entire block of code.

            – W.F.
            Nov 23 '18 at 10:27















            @tom Once again I'd like to state that mentioning abbreviated lambda here is rather to point you to the direction of proposing new feature to the language as none of currently available nor the proposal I know of would suit your desired syntax.

            – W.F.
            Nov 23 '18 at 10:31







            @tom Once again I'd like to state that mentioning abbreviated lambda here is rather to point you to the direction of proposing new feature to the language as none of currently available nor the proposal I know of would suit your desired syntax.

            – W.F.
            Nov 23 '18 at 10:31













            2














            You can do to some extent what you want with requires-expressions (https://godbolt.org/z/6FDT45):



            template <typename T> requires requires(T t) { { 2 * t } -> T; }
            T twice(T t) {
            return 2 * t;
            }

            int main()
            {
            twice(1.0);
            twice("hello"); // Error: Constraints not satisfied
            }


            As you noted in the comments, a helper function cannot be used to avoid writting the function body twice, because
            errors in the implementation are not found until instantiation time. However, requires expressions benefit from
            advantages over decltype(expr) trailing return types:




            • They are not limited to return types.

            • There can be as many expressions as needed.


            What you would like to have is referred to as "concept definition checking". Bjarne Stroustrup discusses why it is
            missing in the concepts design in the paper P0557R0
            (Section 8.2).






            share|improve this answer


























            • I do not need require for that, I can as easily do auto twice(T t) -> decltype(2*t) {...}. The problem is that you have to write the function body twice! This does not scale to more complicated functions.

              – tom
              Nov 23 '18 at 8:37











            • @tom Well. You can write a helper function, maybe in a detail namespace, and invoke it in a requires expression.

              – metalfox
              Nov 23 '18 at 8:41






            • 1





              @tom. It does work. Here's a link for you to try.

              – metalfox
              Nov 23 '18 at 8:48






            • 1





              Nope it does not work. It does not remove the function from the overload set. To test that, I define the twice function without the require, if the require is not satisfied then the unconstrained version should be called. However, calling twice("hello") gives a compiler error instead of calling the unconstrained version. Have a look: godbolt.org/z/LvMXQi

              – tom
              Nov 23 '18 at 9:13






            • 1





              @tom Right. Take a look to my edit ;-)

              – metalfox
              Nov 23 '18 at 9:35
















            2














            You can do to some extent what you want with requires-expressions (https://godbolt.org/z/6FDT45):



            template <typename T> requires requires(T t) { { 2 * t } -> T; }
            T twice(T t) {
            return 2 * t;
            }

            int main()
            {
            twice(1.0);
            twice("hello"); // Error: Constraints not satisfied
            }


            As you noted in the comments, a helper function cannot be used to avoid writting the function body twice, because
            errors in the implementation are not found until instantiation time. However, requires expressions benefit from
            advantages over decltype(expr) trailing return types:




            • They are not limited to return types.

            • There can be as many expressions as needed.


            What you would like to have is referred to as "concept definition checking". Bjarne Stroustrup discusses why it is
            missing in the concepts design in the paper P0557R0
            (Section 8.2).






            share|improve this answer


























            • I do not need require for that, I can as easily do auto twice(T t) -> decltype(2*t) {...}. The problem is that you have to write the function body twice! This does not scale to more complicated functions.

              – tom
              Nov 23 '18 at 8:37











            • @tom Well. You can write a helper function, maybe in a detail namespace, and invoke it in a requires expression.

              – metalfox
              Nov 23 '18 at 8:41






            • 1





              @tom. It does work. Here's a link for you to try.

              – metalfox
              Nov 23 '18 at 8:48






            • 1





              Nope it does not work. It does not remove the function from the overload set. To test that, I define the twice function without the require, if the require is not satisfied then the unconstrained version should be called. However, calling twice("hello") gives a compiler error instead of calling the unconstrained version. Have a look: godbolt.org/z/LvMXQi

              – tom
              Nov 23 '18 at 9:13






            • 1





              @tom Right. Take a look to my edit ;-)

              – metalfox
              Nov 23 '18 at 9:35














            2












            2








            2







            You can do to some extent what you want with requires-expressions (https://godbolt.org/z/6FDT45):



            template <typename T> requires requires(T t) { { 2 * t } -> T; }
            T twice(T t) {
            return 2 * t;
            }

            int main()
            {
            twice(1.0);
            twice("hello"); // Error: Constraints not satisfied
            }


            As you noted in the comments, a helper function cannot be used to avoid writting the function body twice, because
            errors in the implementation are not found until instantiation time. However, requires expressions benefit from
            advantages over decltype(expr) trailing return types:




            • They are not limited to return types.

            • There can be as many expressions as needed.


            What you would like to have is referred to as "concept definition checking". Bjarne Stroustrup discusses why it is
            missing in the concepts design in the paper P0557R0
            (Section 8.2).






            share|improve this answer















            You can do to some extent what you want with requires-expressions (https://godbolt.org/z/6FDT45):



            template <typename T> requires requires(T t) { { 2 * t } -> T; }
            T twice(T t) {
            return 2 * t;
            }

            int main()
            {
            twice(1.0);
            twice("hello"); // Error: Constraints not satisfied
            }


            As you noted in the comments, a helper function cannot be used to avoid writting the function body twice, because
            errors in the implementation are not found until instantiation time. However, requires expressions benefit from
            advantages over decltype(expr) trailing return types:




            • They are not limited to return types.

            • There can be as many expressions as needed.


            What you would like to have is referred to as "concept definition checking". Bjarne Stroustrup discusses why it is
            missing in the concepts design in the paper P0557R0
            (Section 8.2).







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 23 '18 at 10:49

























            answered Nov 23 '18 at 8:27









            metalfoxmetalfox

            1,994420




            1,994420













            • I do not need require for that, I can as easily do auto twice(T t) -> decltype(2*t) {...}. The problem is that you have to write the function body twice! This does not scale to more complicated functions.

              – tom
              Nov 23 '18 at 8:37











            • @tom Well. You can write a helper function, maybe in a detail namespace, and invoke it in a requires expression.

              – metalfox
              Nov 23 '18 at 8:41






            • 1





              @tom. It does work. Here's a link for you to try.

              – metalfox
              Nov 23 '18 at 8:48






            • 1





              Nope it does not work. It does not remove the function from the overload set. To test that, I define the twice function without the require, if the require is not satisfied then the unconstrained version should be called. However, calling twice("hello") gives a compiler error instead of calling the unconstrained version. Have a look: godbolt.org/z/LvMXQi

              – tom
              Nov 23 '18 at 9:13






            • 1





              @tom Right. Take a look to my edit ;-)

              – metalfox
              Nov 23 '18 at 9:35



















            • I do not need require for that, I can as easily do auto twice(T t) -> decltype(2*t) {...}. The problem is that you have to write the function body twice! This does not scale to more complicated functions.

              – tom
              Nov 23 '18 at 8:37











            • @tom Well. You can write a helper function, maybe in a detail namespace, and invoke it in a requires expression.

              – metalfox
              Nov 23 '18 at 8:41






            • 1





              @tom. It does work. Here's a link for you to try.

              – metalfox
              Nov 23 '18 at 8:48






            • 1





              Nope it does not work. It does not remove the function from the overload set. To test that, I define the twice function without the require, if the require is not satisfied then the unconstrained version should be called. However, calling twice("hello") gives a compiler error instead of calling the unconstrained version. Have a look: godbolt.org/z/LvMXQi

              – tom
              Nov 23 '18 at 9:13






            • 1





              @tom Right. Take a look to my edit ;-)

              – metalfox
              Nov 23 '18 at 9:35

















            I do not need require for that, I can as easily do auto twice(T t) -> decltype(2*t) {...}. The problem is that you have to write the function body twice! This does not scale to more complicated functions.

            – tom
            Nov 23 '18 at 8:37





            I do not need require for that, I can as easily do auto twice(T t) -> decltype(2*t) {...}. The problem is that you have to write the function body twice! This does not scale to more complicated functions.

            – tom
            Nov 23 '18 at 8:37













            @tom Well. You can write a helper function, maybe in a detail namespace, and invoke it in a requires expression.

            – metalfox
            Nov 23 '18 at 8:41





            @tom Well. You can write a helper function, maybe in a detail namespace, and invoke it in a requires expression.

            – metalfox
            Nov 23 '18 at 8:41




            1




            1





            @tom. It does work. Here's a link for you to try.

            – metalfox
            Nov 23 '18 at 8:48





            @tom. It does work. Here's a link for you to try.

            – metalfox
            Nov 23 '18 at 8:48




            1




            1





            Nope it does not work. It does not remove the function from the overload set. To test that, I define the twice function without the require, if the require is not satisfied then the unconstrained version should be called. However, calling twice("hello") gives a compiler error instead of calling the unconstrained version. Have a look: godbolt.org/z/LvMXQi

            – tom
            Nov 23 '18 at 9:13





            Nope it does not work. It does not remove the function from the overload set. To test that, I define the twice function without the require, if the require is not satisfied then the unconstrained version should be called. However, calling twice("hello") gives a compiler error instead of calling the unconstrained version. Have a look: godbolt.org/z/LvMXQi

            – tom
            Nov 23 '18 at 9:13




            1




            1





            @tom Right. Take a look to my edit ;-)

            – metalfox
            Nov 23 '18 at 9:35





            @tom Right. Take a look to my edit ;-)

            – metalfox
            Nov 23 '18 at 9:35


















            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%2f53441832%2fsfinae-for-function-body%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







            這個網誌中的熱門文章

            Tangent Lines Diagram Along Smooth Curve

            Yusuf al-Mu'taman ibn Hud

            Zucchini