Declaring member function using function type syntax
Asked Answered
M

1

10

Just recently I learned that you can declare a function (including methods) using variable-like syntax with function type:

using function_type = int (double);
// pre-C++11:
//typedef int function_type(double);

function_type fun_global;

struct methods
{
    static function_type mem_fun_static;
    function_type mem_fun_normal;
    virtual function_type mem_fun_virtual;
    virtual function_type mem_fun_abstract = 0;
};

In above code

  • fun_global is a global function,
  • mem_fun_static is a static member function,
  • mem_fun_normal is an ordinary method,
  • mem_fun_virtual is a virtual method,
  • mem_fun_abstract is an abstract method.

All of them take single argument of type double and return int value - just like the function_type says.

All this years I know C++ and I didn't know about this - this language never stops surprising me! By the way - is this syntax mentioned anywhere here? I don't see this...

However, while exploring this new to me feature I stumbled upon some inconsistencies between compilers. For tests, I was using following compilers:

  • GCC 5.4.0 and 7.1.0, command line: g++ -Wall -Wextra -pedantic -std=c++14
  • Clang 4.0.1, command line: clang++ -Wall -Wextra -pedantic -std=c++14
  • MSVC 19.10.25019 (VS 2017), command line: cl /W4 /EHsc

In tests that I run both GCC versions gave same result so further I'm referring to them just as GCC.


= delete inconsistency

struct methods
{
    /* ... */
    function_type mem_fun_deleted = delete;
};
  • GCC: OK
  • Clang: error!

    Test.cpp:13:34: error: '= delete' is a function definition and must occur in a standalone declaration
            function_type mem_fun_deleted = delete;
                                            ^
    1 error generated.
    
  • MSVC: OK

= default inconsistency

struct methods
{
    /* ... */
    using assignment_type = methods& (methods const&);
    assignment_type operator= = default;
};
  • GCC: OK
  • Clang: error!

    Test.cpp:14:30: error: '= default' is a function definition and must occur in a standalone declaration
            assignment_type operator= = default;
                                        ^
    1 error generated.
    
  • MSVC: error!

    Test.cpp(14): error C2206: 'methods::operator =': typedef cannot be used for function definition
    

Inline definition inconsistency

struct methods
{
    /* ... */
    function_type mem_fun_inline { return 0; }
};
  • GCC: error!

    Test.cpp:13:43: error: invalid initializer for member function ‘int methods::mem_fun_inline(double)’
      function_type mem_fun_inline { return 0; }
                                               ^
    Test.cpp:13:43: error: expected ‘;’ at end of member declaration
    
  • Clang: error!

    Test.cpp:13:33: error: expected expression
            function_type mem_fun_inline { return 0; }
                                           ^
    Test.cpp:7:8: error: missing '}' at end of definition of 'methods'
    struct methods
           ^
    /usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include/c++/x86_64-pc-cygwin/bits/c++config.h:194:1: note: still within definition of 'methods' here
    namespace std
    ^
    2 errors generated.
    
  • MSVC: OK


Questions

Which compilers are right here?

Furthermore, is it possible to:

  1. In the inline definition (supported only by MSVC) refer somehow to the argument?
  2. Somehow use the function_type also at definition of those functions (when done outside of the class). Following is OK (with all compilers)

    struct methods
    {
        static function_type mem_fun_static;
        /* ... */
    };
    
    int methods::mem_fun_static(double) { return 0; }
    

    It is not that bad since change of function_type should result in compilation error at function definition (as it will no longer match declaration) - but still maybe it is possible to avoid even that.

Milagrosmilam answered 13/7, 2017 at 8:3 Comment(11)
Nice question! Was aware of it, but saw little practical use beyond specifying the types of expected callback functions (mostly in C code as well).Simply
@StoryTeller That is actually how I found it out! - "thread main" callback with the framework we have.Milagrosmilam
Amazing how the forward declarations of those functions become self explanatory, isn't it? I also like that pointer semantics aren't being hidden behind an alias.Simply
BTW, it can also be used as a type parameter to std::function. Again, more self documenting code.Simply
While phrased differently, this is basically a duplicate of Why can't a typedef of a function be used to define a function?Hellenism
@Hellenism - I disagree. That question is about the rationale for the standard's position. This is about "what is the standard's position".Simply
@StoryTeller I kinda see what you mean, but to me, 'Can I do X?' is a subset of 'Why can I not do X?'; an answer explaining the position inherently identifies what it is. If the latter has already been answered, then IMO we don't need the former.Hellenism
@Hellenism Before asking I was searching and did not find that one. :(Milagrosmilam
@AdamBadura It may not have been your fault! I sometimes find that Googling for foo bar stackoverflow produces more useful results than SO's own duplicate-finder, which is unfortunate but still a handy backup.Hellenism
@Hellenism But at least my question adds comparison between 3 compilers and perhaps someone should now issue bug tickets against MSVC and GCC. :)Milagrosmilam
@AdamBadura I tend to nominate the person who found the bugs to report them... :PHellenism
T
5

§ 8.3.5 Functions [dcl.fct] p12 A typedef of function type may be used to declare a function but shall not be used to define a function.

Thus Clang is right to reject the code in all cases and compilers that accept it are in the wrong.

(The quotation is from N4618 but the rule is a part of the language since forever).

Terzetto answered 13/7, 2017 at 9:12 Comment(3)
What revision are you quoting? Could you please add the section name as well? (Section names are stable across revisions, numbers not so much).Simply
I'm surprised that = delete counts as function definition. If you could provide a quote for that as well it would be even better. But your answer answers it all, so thanks!Milagrosmilam
@AdamBadura 8.4.3 [dcl.fct.def.delete] "A function definition of the form ... is called a deleted definition".Terzetto

© 2022 - 2024 — McMap. All rights reserved.