简体   繁体   中英

Difference between “explicit” and “implicit” invocation of operator ()

Is there a clause in standard describing the following difference between a ways to call operator () from base classes?

#include <iostream>
#include <type_traits>

#include <cstdlib>
#include <cassert>

template< typename visitor, typename ...visitors >
struct composite_visitor
    : std::decay_t< visitor >
    , composite_visitor< visitors... >
{

    //using std::decay_t< visitor >::operator ();
    //using composite_visitor< visitors... >::operator ();

    composite_visitor(visitor && _visitor, visitors &&... _visitors)
        : std::decay_t< visitor >(std::forward< visitor >(_visitor))
        , composite_visitor< visitors... >{std::forward< visitors >(_visitors)...}
    { ; }

};

template< typename visitor >
struct composite_visitor< visitor >
    : std::decay_t< visitor >
{

    //using std::decay_t< visitor >::operator ();

    composite_visitor(visitor && _visitor)
        : std::decay_t< visitor >(std::forward< visitor >(_visitor))
    { ; }

};

template< typename visitor, typename ...visitors >
composite_visitor< visitor, visitors... >
compose_visitors(visitor && _visitor, visitors &&... _visitors)
{
    return {std::forward< visitor >(_visitor), std::forward< visitors >(_visitors)...};
}

int
main()
{
    struct A {};
    struct B {};
#if 1
    struct { int operator () (A) { return 1; } } x;
    struct { int operator () (B) { return 2; } } y;
    auto xy = compose_visitors(x, y);
#else
    auto xy = compose_visitors([] (A) { return 1; }, [] (B) { return 2; });
#endif
    // "implicit":
    assert(xy(A{}) == 1);
    assert(xy(B{}) == 2);
    // "explicit":
    assert(xy.operator () (A{}) == 1); // error: member 'operator()' found in multiple base classes of different types
    assert(xy.operator () (B{}) == 2);
    return EXIT_SUCCESS;
}

"Implicit" invocation compiles fine, but not the "explicit". Why is it so?

compose_visitors combine the arguments into single class by means of construction of a class derived from all of them.

Uncommenting the using derectives removes the hard error. It is clear.

The behaviour is identical for lambda functions and for functors.

Compiler is clang 3.6 .

The "implicit" invocation is also ill-formed. In fact, GCC rejects it , so it seems like a bug in Clang.

The standard (N4140, [over.call]/1) clearly says that

a call x(arg1,...) is interpreted as x.operator()(arg1, ...) for a class object x of type T if T::operator()(T1, T2, T3) exists and if the operator is selected as the best match function by the overload resolution mechanism (13.3.3).

So the two invocations must behave identically.

Update : this is a known issue in Clang.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM