Why can't operator () of stateless functor be static?

前端 未结 5 1024
我在风中等你
我在风中等你 2020-12-15 19:51

Why is operator () of stateless functor not allowed to be static? Stateless lambda objects are convertible to pointers to free functions having the

相关标签:
5条回答
  • 2020-12-15 20:10

    I would think that there's no technical reason to forbid this (but not being familiar with the de-facto cross-vendor C++ ABI (Itanium ABI), I can't promise anything).

    There's however an evolutional issue about this at https://cplusplus.github.io/EWG/ewg-active.html#88 . It even has the [tiny] mark on it, making it a somewhat "trivial" feature under consideration.

    0 讨论(0)
  • 2020-12-15 20:11

    I can't see any technical reason to forbid a static auto operator()( ... ). But it's a special case, so it would complicate the standard to add support for it. And such complication is not necessary, because it's very easy to emulate:

    struct L
    {
        static void func() {}
    
        void operator()() const { func(); }
    
        operator auto () const
        { 
            return &L::func;
        }
    };
    

    See Johannes' answer for some possibly useful extra info.

    0 讨论(0)
  • 2020-12-15 20:14

    A simple, a little bit dirty workaround until the relevant committee considers this trivial feature:

    Glob operators are syntactically similar to the constructors.

    Thus, you can't write a

    static MyClass::operator()(...);
    

    It was made simply impossible, because a committee decided so on unclear reasons. I would be so happy if I could talk with one of their members, to ask, what was in their mind as they decided so. Unfortunately, he probably wouldn't understand my question, because he never programmed c++. He only worked on its docs.

    Now they need some decades of

    • debates
    • consultations
    • meetings
    • and considerations

    to implement a trivial feature. I suspect the feature may be made available around in c++3x, and on emulated machines it may be even tried out.

    Until then, you can try to write:

    MyClass::MyClass(...);
    

    In both cases you can call MyClass(...);.

    Of course it is useful mainly if MyClass is a singleton. And, I would say it is a hack. Furthermore, it allocates a sizeof(MyClass) on the stack which may be bad in the performance / efficiency side.


    Furthermore, this will be in essence a constructor, and constructors can't return anything. But you can avoid this by storing the result in the instance, and then casting it by a cast operator to anything you wish to.

    0 讨论(0)
  • 2020-12-15 20:15

    Per standard 13.5/6,

    An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration.

    Additionally, in 13.5.4 it is stated that

    operator() shall be a non-static member function with an arbitrary number of parameters. It can have default arguments. It implements the function call syntax postfix-expression ( expression-list opt ) where the postfix-expression evaluates to a class object and the possibly empty expression-list matches the parameter list of an operator() member function of the class. Thus, a call x(arg1,...) is interpreted as x.operator()(arg1, ...) for a class object x of type T

    0 讨论(0)
  • 2020-12-15 20:29

    Like the others, I don't see a fundamental reason why it is not possible.

    (EDIT 2020: Just found this proposal http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1169r0.html)

    In some cases might conflict, according to other rules, with member/static overloading which is not allowed in C++ (again, not sure why).

    struct A{
      void f();
      static int f(); // compile error 
    }
    

    So even if it were allowed to have a static operator(), should this be permitted?

    struct A{
      void operator()();
      static int operator()(); // should be a compiler error??? 
    }
    

    Anyway, there is only one true reason to have a static operator() that it is not purely a syntactic reason and it is that objects should be able to call static functions as if they were member functions.

    struct A{
       static int f():
    }
    ...
    A a; 
    a.f(); // calls A::f() !!!
    

    Specifically, the user of the class A doesn't need to know if a function is implemented as static or as a member. It can later be upgraded to a member function from a generic point of view.

    Leaving that important application to generic programming aside, there is a workaround the leads to a similar syntax that I saw in https://quuxplusone.github.io/blog/2018/03/19/customization-points-for-functions/, and that is to have a static member function called _, a name that doesn't imply any meaning.

    struct A{
        static int _();
    }
    ...
    A::_(); // instead of the more desirable (?) A::() or A::operator()
    a._(); // this invokes the static functon _ 
    

    Instead of the more desirable A::() or A::operator(), (well are they desirable at all? I don't know; something like A() would be really interesting but doens't even follow the syntax of a static function and can be confused with a constructor).

    (As I said, the only feature I still miss, regarding this limitation you point out, is that a() cannot automatically delegate to a static version of the operator(), e.g. A::operator().)

    In summary, your code could look like this:

    struct L{
        static void _() const {} 
        operator auto () const{ 
            return L::_();
        }
    };
    
    L ell; 
    ell(); // calls L::_() really.
    

    Not sure what are willing to achieve still.

    0 讨论(0)
提交回复
热议问题