operator()的"显式"和"隐式"调用之间的区别

Ori*_*ent 1 c++ inheritance c++11 c++14

标准中是否有一个子句描述了operator ()从基类调用的方法之间的以下区别?

#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;
}
Run Code Online (Sandbox Code Playgroud)

"隐式"调用编译良好,但不是"显式".为什么会这样?

compose_visitors 通过构造从所有这些派生的类来将参数组合成单个类.

取消注释usingderectives可以消除硬错误.很明显.

lambda函数和仿函数的行为是相同的.

编译器是铿锵声3.6.

Ant*_*vin 7

"隐式"调用也是不正确的.事实上,GCC拒绝它,所以它似乎是Clang中的一个错误.

标准(N4140,[over.call]/1)清楚地说明了这一点

呼叫x(arg1,...)被解释为x.operator()(arg1, ...)一类对象x类型的T,如果T::operator()(T1, T2, T3)存在,并且如果操作者被选择作为由过载解析机制(13.3.3)的最佳匹配函数.

所以这两个调用必须表现相同.

更新:这是Clang中的一个已知问题.