Why can't operator () of stateless functor be

2019-01-24 05:04发布

问题:

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

Stephan T. Lavavej on p. 6 points out that conversion to a function pointer is just an operator FunctionPointer() (cite). But I can't obtain a corresponding pointer to operator () as to non-member function. For functor struct F { void operator () () {} } it seems to be impossible to convert &F::operator () to instance of type using P = void (*)();.

Code:

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

The error is

overloaded 'operator()' cannot be a static member function

but operator () is not overloaded.

回答1:

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



回答2:

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.



回答3:

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.



回答4:

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.