Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What is the best way to resolve the Warning re: multiple matches for a function? #289

Closed
SylvainCorlay opened this issue Nov 25, 2016 · 20 comments · Fixed by #606
Closed
Assignees
Labels
bug Problem in existing code code Source code

Comments

@SylvainCorlay
Copy link
Contributor

WARNING: doxygenfunction: Unable to resolve multiple matches for function

@SylvainCorlay SylvainCorlay changed the title What is the best way to resolve the Warning re: multiple match functions? What is the best way to resolve the Warning re: multiple matches for a function? Nov 25, 2016
@michaeljones
Copy link
Collaborator

Hey, good question. Normally by providing more details about the function arguments. If you're only supplying the function name and it is an overloaded function then you will get that warning (I think!) so you have to provide the full signature that matches the overload that you want.

That is off the top of my head, does it seem to fit your case?

@SylvainCorlay
Copy link
Contributor Author

In my case, it is a template function that is specialized for multiple types.

@michaeljones
Copy link
Collaborator

Ok, I'm not sure that has been tested properly. Would you consider providing a test case in the examples section and would reproduce the issue that you are seeing?

@SylvainCorlay
Copy link
Contributor Author

SylvainCorlay commented Dec 2, 2016

Simply overriding a function foo like this does the trick:

namespace bar
{
    template <class T>
    auto xt::foo(T);

    template <class T>
    auto xt::foo(std::vector<T>);
}

and

.. doxygenfunction:: bar::foo
   :project: baz

yields

WARNING: doxygenfunction: Unable to resolve multiple matches for function "bar::foo"
with arguments () in doxygen xml output for project "baz" from directory: ../xml.
Potential matches:
    - template <class T>
      auto bar::foo(T)
    - template <class T>
      auto bar::foo(std::vector<T>)

@JohanMabille
Copy link
Contributor

JohanMabille commented Feb 24, 2017

The following should fix the problem:

.. doxygenfunction:: bar::foo(T)
   :project: baz

.. doxygenfunction:: bar::foo(std::vector<T>)
   :project: baz

You have to be very careful with white spaces so the doxygenfunction declaration exactly matches the cpp function declaration.

@wolfv
Copy link

wolfv commented Mar 21, 2017

Is there another way to distinguish functions? I have the same problem with functions that are enable_if'd based on the template type.

E.g.:

    /**
     * Force evaluation of xexpression.
     * @return xarray or xtensor depending on shape type
     * 
     * \code{.cpp}
     * xarray<double> a = {1,2,3,4};
     * auto&& b = xt::eval(a); // b is a reference to a, no copy!
     * auto&& c = xt::eval(a + b); // c is xarray<double>, not an xexpression
     * \endcode
     */
    template <class T>
    inline auto eval(T&& t)
        -> std::enable_if_t<detail::is_container<std::decay_t<T>>::value, T&&>
    {
        return t;
    }

    template <class T, class I = std::decay_t<T>>
    inline auto eval(T&& t)
        -> std::enable_if_t<!detail::is_container<I>::value && detail::is_array<typename I::shape_type>::value, xtensor<typename I::value_type, std::tuple_size<typename I::shape_type>::value>>
    {
        return xtensor<typename I::value_type, std::tuple_size<typename I::shape_type>::value>(std::forward<T>(t));
    }

The signature is obviously exactly the same, but I'd like to select the first one to get the documentation from.

@JohanMabille
Copy link
Contributor

Using the @cond / @endcond doxygen directive around the overloads prevents Doxygen from parsing them and solves this issue.

@fmorgner
Copy link

fmorgner commented Sep 2, 2017

On a similar note, I can't seem to be able to reference the second overload in the following case:

namespace dab
  {
  struct device
    {
    virtual bool gain(gain gain) = 0;
    virtual dab::gain gain() const = 0;
    };
  }

What would be the appropriate way to reference the second overload? I tried:

  • .. doxygenfunction:: dab::device::gain()
  • .. doxygenfunction:: dab::device::gain() const
  • .. doxygenfunction:: virtual dab::gain dab::device::gain() const

but none of them work.

The first two give the error, that there are multiple candidates, while the third one (obviously) can't resolve the function.

@wolfv
Copy link

wolfv commented Oct 18, 2017

I also found that leaving the argument names in the signature (in the rst) creates this error.
Maybe removing the argument names from the rst input could help some subset of users who just copy-pastes the signature from C++.

@vermeeren vermeeren added enhancement Improvements, additions (also cosmetics) code Source code labels Jun 2, 2018
@vermeeren
Copy link
Collaborator

Primarily because of @wolfv 's comment above I think this can be improved in Breathe. Either by stripping names somehow or at the very least documenting this behaviour better.

@pitrou
Copy link

pitrou commented Dec 11, 2018

I've got this issue too. The way I'm working around it is by putting the various overloads in a dedicated Doxygen group, and by using doxygengroup instead of doxygenfunction:

.. doxygengroup:: buffer-allocation-functions
   :project: arrow_cpp
   :content-only:

However, it would be nice to automatically emit documentation for all overloads of a function (perhaps using a separate directive or a dedicated option to doxygenfunction?).

@koniarik
Copy link

Got this problem recently, but I am in somehow "mixed" situation.

I really do not like breathes index, so I am writing my python script to parse doxygen .xml and generate appropiate .rst structure I want. (Which btw is much simpler than expected)

Thing is: given that I actually do have specific refid of the overload (algorithm_8h_1a5861adad19739be6645aa5e03f032f77) is there a sane way to load the function by this? (or any other parameter in .xml of that namespace)

@5p4k
Copy link

5p4k commented Apr 27, 2020

I also encountered this when using the detection idiom, although in my case it's in combination with #441 :

/** @brief Well defined only if @p T has an invocable function \::something(void)
 */
template <class T>
auto test_something(int) -> decltype(std::declval<T>().something(), std::true_type{});

/** @brief Fallback, if @p T doesn't have \::something(void), will match this
 */
template <class>
std::false_type test_something(...);

/** Tests whether the given type has a \::something(void) method.
 */
template <class T>
using has_something = decltype(test_something<T>(0));

Gives rise to this:

./respiration_issues/docs/api/function_detect__idiom_8h_1a2298a2bb5c4964236303a599d5091d1c.rst:13: WARNING: Invalid C++ declaration: Expected end of definition. [error at 52]
  template<class T> auto detect::test_something (int) -> decltype(std::declval< T >().something(), std::true_type
  ----------------------------------------------------^
./respiration_issues/docs/api/function_detect__idiom_8h_1a2298a2bb5c4964236303a599d5091d1c.rst:13: WARNING: Duplicate declaration, template<class> std::false_type detect::test_something (...)
./respiration_issues/docs/api/function_detect__idiom_8h_1a69d042d6bb253247bd7b81706d6abbc6.rst:13: WARNING: Invalid C++ declaration: Expected end of definition. [error at 52]
  template<class T> auto detect::test_something (int) -> decltype(std::declval< T >().something(), std::true_type
  ----------------------------------------------------^
./respiration_issues/docs/api/function_detect__idiom_8h_1a69d042d6bb253247bd7b81706d6abbc6.rst:13: WARNING: Duplicate declaration, template<class> std::false_type detect::test_something (...)
./respiration_issues/docs/api/function_detect__idiom_8h_1a69d042d6bb253247bd7b81706d6abbc6.rst:13: WARNING: doxygenfunction: Unable to resolve multiple matches for function "detect::test_something" with arguments (int) in doxygen xml output for project "Test" from directory: ./doxyoutput/xml.
Potential matches:
    - template<class T> auto detect::test_something (int) -> decltype(std::declval< T >().something(), std::true_type
    - template<class>
      std::false_type detect::test_something(...)

I'm not sure how to apply the comments above to this specific case. The two doxygenfunction are missing the return value but are correct (I am using Breathe through Exhale):

  • .. doxygenfunction:: detect::test_something(int)
  • .. doxygenfunction:: detect::test_something(...)

@yaqwsx
Copy link

yaqwsx commented May 3, 2020

I have a problem that is related, therefore I will put it here instead of opening a new issue. I am also not sure if it is more breathe or sphinx related issue.

I have the following C++ overload:

template< typename T, typename Visitor >
auto visit( T& object, Visitor visitor ) -> std::enable_if_t<
    std::is_base_of_v< typename T::VisitorType, Visitor >,
    typename Visitor::ReturnType >
{
    object.accept( visitor );
    if constexpr ( !std::is_same_v< void, typename Visitor::ReturnType > )
        return visitor.result;
}

template < typename T, typename... Fs >
auto visit( T& object, Fs... fs ) {
    return visit( object, T::VisitorType::make( fs... ) );
}

When I put them in my .rst like this:

.. doxygenfunction:: atoms::visit(T &object, Fs... fs)
    :project: lib

.. doxygenfunction:: atoms::visit(T &object, Visitor visitor) -> std::enable_if_t<std::is_base_of_v<typename T::VisitorType, Visitor>, typename Visitor::ReturnType>
    :project: lib

I get the following warning:

/home/xmrazek7/projects/RoFI-newConf/doc/rofilib/atoms/patterns.rst:125: WARNING: Duplicate declaration, template<typename T, typename... Fs> auto atoms::visit (T &object, Fs... fs)
/home/xmrazek7/projects/RoFI-newConf/doc/rofilib/atoms/patterns.rst:128: WARNING: Duplicate declaration, template<typename T, typename Visitor> auto atoms::visit (T &object, Visitor visitor) -> std::enable_if_t< std::is_base_of_v< typename T::VisitorType, Visitor >, typename Visitor::ReturnType >
/home/xmrazek7/projects/RoFI-newConf/doc/rofilib/atoms/patterns.rst:128: WARNING: Duplicate declaration, template<typename T, typename Visitor> auto atoms::visit (T &object, Visitor visitor) -> std::enable_if_t< std::is_base_of_v< typename T::VisitorType, Visitor >, typename Visitor::ReturnType >

But the generated documentation seems to be correct. I think the warning is a bug. Is there a way to solve this warning? I am using the latest version of sphinx from branch "3.x" and breathe version 4.1.18 (PyPi latest version).

@jakobandersen
Copy link
Collaborator

I'm quite sure this is a Breathe issue. From #512:
It looks like the doxygenfunction directive results in Duplicate declaration warnings. I believe the problem is that Breathe renders function declarations twice, once to figure out if the function
is actually selected by the directive (directives.py:237), and then secondly to actual rendering into the output. The first round is discarded. Instead of the full rendering it may be possible to use the Sphinx C++ parser directly to essentially do the same trick.
My best guess is that this is the issue reported in #504. It looks like this PR breaks the current trick when function templates are involved.

If I understand correctly, the idea is that doxygenfunction either takes a name, or a name with a parameter list (I can't seem to find a documentation page for this at the moment). This should be fixable, though I don't think it will cover all cases. For example:

template<typename T, typename std::enable_if<sizeof(T) == 1>::type* = nullptr> void f(T t);
template<typename T, typename std::enable_if<sizeof(T) != 1>::type* = nullptr> void f(T t);

Here the overloading is due to differences in the template parameter lists. So I guess there should be a third shape the directive argument can take, which is a full function signature?

@yaqwsx
Copy link

yaqwsx commented May 4, 2020

I think having the third option makes sense for C++. Also, what would make sense to me is to have a directive, which wouldn't issue a warning but instead, listed all the overloads of function/class/struct.

@jakobandersen
Copy link
Collaborator

After a bit more thinking, I think this is a bit more complicated. The doxygenfunction directive doesn't know which language it is fetching functions from. Right now it always uses :: as separator in nested names, so if you are using it for other languages then you must still use ::, which will then be rendered according to the ordinary syntax for that language. I guess few people use Breathe for Python (not sure about the scoping in PHP), so this is not a problem.
The domain is only available once a candidate is found, but if full declarations should be recognized it need to know how to switch domain before lookup. Would it be ok to require a :domain: option on the directive if a nested name is given as argument? And perhaps add a breathe_default_function_domain = "cpp" config variable to default it globally? Potentially a default domain could also be attached to projects, such that the current :project: option is enough?

@yaqwsx
Copy link

yaqwsx commented May 18, 2020

IMHO having a :domain: option is a nice feature which will turn into a pain if there is no way to provide fault option. Personally I would like to have both - breathe-wide default domain and project default domain.

@vermeeren vermeeren added bug Problem in existing code and removed enhancement Improvements, additions (also cosmetics) labels Dec 11, 2020
@vermeeren vermeeren linked a pull request Dec 11, 2020 that will close this issue
@vermeeren vermeeren linked a pull request Dec 15, 2020 that will close this issue
@vermeeren vermeeren self-assigned this Dec 15, 2020
@vermeeren
Copy link
Collaborator

Fix released in Breathe 4.25.0, let me know if there are any issues still.

@jakobandersen
Copy link
Collaborator

Note, this is technically not fully resolved, but it may be best to open another issue targeted towards the missing pieces, with examples.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Problem in existing code code Source code
Projects
None yet