https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92849

            Bug ID: 92849
           Summary: call to 'operator()' incorrectly considered ambiguous,
                    when inherited twice with different type parameters
           Product: gcc
           Version: 9.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: kholdstare0.0 at gmail dot com
  Target Milestone: ---

Minimal test case:

    #include <type_traits>

    template <typename Signature>
    struct declfunc;

    template <typename Result, typename... Args>
    struct declfunc<Result(Args...)>
    {
        Result operator() (Args...);
    };

    template <typename... Signatures>
    struct decloverload
        : declfunc<Signatures>...
    { };

    using overload_set = decloverload<void(int), void(int, int)>;
    static_assert(std::is_invocable_v<overload_set, int>);

Expected result: compilation succeeds. See the godbolt link below, and try it
with clang - clang accepts the code since version 4

Actual result:

/opt/compiler-explorer/gcc-9.2.0/include/c++/9.2.0/type_traits:2336:26: error:
request for member 'operator()' is ambiguous

 2336 |       std::declval<_Fn>()(std::declval<_Args>()...)

      |       ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~

<source>:9:16: note: candidates are: 'Result declfunc<Result(Args
...)>::operator()(Args ...) [with Result = void; Args = {int, int}]'

    9 |         Result operator() (Args...);

      |                ^~~~~~~~

<source>:9:16: note:                 'Result declfunc<Result(Args
...)>::operator()(Args ...) [with Result = void; Args = {int}]'

<source>:18:24: error: static assertion failed

   18 |     static_assert(std::is_invocable_v<overload_set, int>);

      |                   ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Compiler returned: 1


Godbolt link with test case as well as '-E' preprocessor output:
https://godbolt.org/z/D9nTBr


I suspect the ambiguity comes from the fact that two call operators are
inherited from the same class (`declfunc` in this case), and the call operators
"look the same" - i.e both are `Result operator() (Args...)`. However since
`declfunc` is instantiated with different template paramaters, the concrete
instances of the call operators are in fact different - Args is `{int}` in one
case and `{int, int}` in another. The compiler mentions this in the error
message. Perhaps the overload check should descend deeper (using the concrete
parameters for `Args...`)

Reply via email to