为什么any_cast函数重载不会引起歧义?

时间:2016-12-26 17:06:04

标签: c++ templates overloading boost-any

Boost的<boost/any.hpp>有:

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

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

(以及其他变种。)这种组合不应该导致boost::any_cast<int>(my_any);等电话的含糊不清吗?

我问,因为如果我写这个程序:

#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;
}

我得到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)
               ^~~~~~~~

2 个答案:

答案 0 :(得分:5)

为什么电话会不明确?调用函数的方式any参数是左值。因此,any参数将为const - 限定在这种情况下第二次重载是唯一的潜在匹配或不是const - 在这种情况下第一次重载更好匹配(当第二次重载需要从any&转换为any const&时,不需要转换。如果使用临时any调用该函数,它可以绑定到右值超载(即,取any&&),或者,如果不存在,则它可以绑定到const - 限定的重载,但不是非const - 限定的重载,同样,不会造成任何歧义。

实际上,这里发生了一些有趣的事情:没有全局命名空间中的重载,使用显式模板参数的函数不能使用!但是,只要存在任何功能模板,即使是不匹配的功能模板,也可以使用 !这是一个例子:

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);
}

答案 1 :(得分:0)

我不认为这个问题与提升或任何问题有关。您要问的是标准的运算符/模板重载/选择规则,该规则在c ++中定义良好(如果不是编译器则会抛出错误。

  1. 如果您的任何值被声明为const,则使用第二个模板。

  2. 否则第一个是。

  3. 这是有道理的,并且比这个具体问题更为通用。 This可能有帮助。