GCC 4.9模糊过载模板专业化

tt2*_*293 16 c++ gcc c++11

我遇到了一个问题gcc 4.9.2(使用-std = c ++ 11)没有编译一段代码,错误信息是

调用重载的'InsertDataIntoInputMap(int&,boost :: shared_ptr&)'是不明确的

该代码使用msvc 2013进行编译

#include <iostream>
#include <map>
#include <boost/shared_ptr.hpp>

struct Proxy
{
    typedef std::map<int, int> InputDataMap;    
    int a;
};

template<class C, class D>
void InsertDataIntoInputMap(
    const typename C::InputDataMap::key_type& key,
    const D val)
{
    std::cout << "Not shared\n";
}

template<class C, class D>
void InsertDataIntoInputMap(
    const typename C::InputDataMap::key_type& key,
    const boost::shared_ptr<D> val)
{
    if (val)
    {
        std::cout << "Shared\n";
    }
}

int main() {
    int a;
    boost::shared_ptr<double> x(new double(4.5));

    InsertDataIntoInputMap<Proxy>(a, x);
}
Run Code Online (Sandbox Code Playgroud)

而以下实际上使用gcc和msvc进行编译:

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

template<class C, class D>
void InsertDataIntoInputMap(
    const C& key,
    const D val)
{
    std::cout << "Not shared\n";
}

template<class C, class D>
void InsertDataIntoInputMap(
    const C& key,
    const boost::shared_ptr<D> val)
{
    if (val)
    {
        std::cout << "Shared\n";
    }
}

int main() {
    int a = 0;
    boost::shared_ptr<double> x(new double(4.5));

    InsertDataIntoInputMap<int>(a, x);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我原本以为编译器应该在两种情况下都使用boost :: shared_ptr参数的函数?

Col*_*mbo 3

这个问题可以简化为偏序中的不精确:仍然考虑和比较其中没有出现涉及推导的模板参数的对。CWG #455#885也解决了该问题。

在您的示例中,重载解析无法区分重载。因此,部分排序是必要的。偏序会尝试进行两次推导,参数类型Ptypename C::InputDataMap::key_type
然而,这种演绎注定会失败,因为C它只出现在非演绎的上下文中。即,来自两个模板(对于该特定对)的类型至少不如来自相应另一个模板的类型那么专业化,这反过来意味着这两个模板都不比另一个更专业。

正如 @TC 所指出的, CWG #1391的决议有所帮助。这部分特别是:

将 14.8.2.4 [temp.deduct.partial] 第 4 段更改如下:

P上面从参数模板中指定的每个类型以及参数模板中的相应类型都用作和的类型A如果特定项P不包含参与模板参数推导的模板参数,则不P用于确定顺序。

现在,第一个参数对在两种情况下都被完全忽略(因为 的类型C仅由显式参数列表确定),并且发现第二个重载更加专门。