GCC 4.9模糊过载模板专业化

时间:2015-07-22 12:30:28

标签: c++ c++11 gcc

我遇到问题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);
}

虽然以下实际上使用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;
}

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

2 个答案:

答案 0 :(得分:3)

这个问题可以简化为部分排序的不精确性:仍然会考虑和比较没有出现与演绎有关的模板参数的对。该问题也由CWG #455#885解决。

在您的示例中,重载解析无法区分重载。因此,部分排序是必要的。部分排序将尝试执行两次推导,参数类型Ptypename C::InputDataMap::key_type 但是,这种推论注定要失败,因为C仅出现在非推断的上下文中。即两个模板(对于该特定对)的类型至少与相应的其他模板中的类型一样专用 - 反过来,这意味着两个模板都不比另一个模板更专业。

正如@ T.C.所述,CWG #1391的解决方案有所帮助。这部分特别是:

  

将14.8.2.4 [temp.deduct.partial]第4段改为:

     

上面从参数模板中提名的每种类型和参数模板中的相应类型都用作PA的类型。 如果特定P不包含参与模板参数扣除的模板参数,则P不会用于确定排序。

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

答案 1 :(得分:1)

一个简单的别名可以使代码工作:

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

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

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

template<class C, class D, class F = typename C::InputDataMap::key_type>
void InsertDataIntoInputMap(
    const F& 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);
}

但是imo。这应该不起作用,因为我认为,草案说,编译器不会考虑C :: InputDataMap -

中的命名空间
class F = typename C::InputDataMap::key_type

和F将是一个非推断的上下文(如key_type)。