简体   繁体   中英

Why don't the any_cast function overloads cause ambiguity?

Boost's <boost/any.hpp> has:

template<typename ValueType>
ValueType any_cast(any & operand);

template<typename ValueType>
inline ValueType any_cast(const any & operand);

(among other variants.) Shouldn't this combination cause ambiguity in calls such as boost::any_cast<int>(my_any); ?

I'm asking because if I write this program:

#include <boost/any.hpp>
#include <iostream>

template<typename ValueType>
ValueType any_cast(boost::any & operand)
{
        return boost::any_cast<ValueType>(operand);
}

int main()
{
        int x = 123;
        boost::any my_any(x);
        std::cout << "my_any = " << any_cast<int>(my_any) << "\n";
        return 0;
}

I do get a complaint about ambiguity :

g++ -std=c++14 -O3 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:14:57: error: call of overloaded 'any_cast(boost::any&)' is ambiguous
         std::cout << "my_any = " << any_cast<int>(my_any) << "\n";
                                                         ^
main.cpp:5:11: note: candidate: ValueType any_cast(boost::any&) [with ValueType = int]
 ValueType any_cast(boost::any & operand)
           ^~~~~~~~
In file included from main.cpp:1:0:
/usr/local/include/boost/any.hpp:281:22: note: candidate: ValueType boost::any_cast(const boost::any&) [with ValueType = int]
     inline ValueType any_cast(const any & operand)
                      ^~~~~~~~
/usr/local/include/boost/any.hpp:258:15: note: candidate: ValueType boost::any_cast(boost::any&) [with ValueType = int]
     ValueType any_cast(any & operand)
               ^~~~~~~~

Why would the calls be ambiguous? The way you call the function the any argument is an lvalue. Thus, the any argument will either be const -qualified in which case the second overload is the only potential match or it is not const -qualified in which case the first overload is the better match (there is no conversion needed while the second overload would need a conversion from any& to any const& ). If you call the function with a temporary any , it could bind to an rvalue overload (ie, taking any&& ) or, if that doesn't exist, it can bind to the const -qualified overload but not the non- const -qualified overload, again, not causing any ambiguity.

Actually, there is something interesting happening here: without the overload in the global namespace the function using the explicit template argument cannot be used! However, as soon as any function template is present, even a non-matching one, it can be used! Here is an example:

namespace foo {
    struct bar {};

    template <typename T> void bar_cast(bar&) {}
    template <typename T> void bar_cast(bar const&) {}
    template <typename T> void bar_cast(bar&&) {}
}

struct whatever;
template <typename T> void bar_cast(whatever);

int main()
{
    foo::bar b;
    bar_cast<int>(b);
}

I don't think this question has anything to do with boost or any. What you're asking is a standard operator/template overload/selection rule which is well defined in c++ (and if not compiler throws an error.

  1. If your any value was declared const the second template is used.

  2. Otherwise the first is.

This makes sense, and is more general than this specific question. This may help.

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