【问题标题】:GCC 4.9 ambiguous overload template specializationGCC 4.9 模棱两可的重载模板特化
【发布时间】:2015-10-12 08:01:46
【问题描述】:

我遇到了一个问题,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 参数的函数?

【问题讨论】:

  • Coliru 无法使用 clang 和 g++ 编译第一个示例。 coliru.stacked-crooked.com/a/d1035dd01513af3a
  • 我开始认为 Clang 和 GCC 在这里是错误的,因为第二个模板函数至少对一个参数专门化,而对另一个参数更专门化,所以无论非推断的上下文。谁能提供更好的解释?
  • @TartanLlama 对于第一个参数,两个方向的推导都失败了,所以两者都不像另一个那样专业?
  • @TartanLlama 我认为是这样,根据当前的措辞。不过,我认为CWG 1391 的 PR 会改变规则。

标签: c++ c++11 gcc


【解决方案1】:

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

在您的示例中,重载解析无法区分重载。因此,部分排序是必要的。并且偏序会尝试进行两次推导,参数类型Ptypename C::InputDataMap::key_type
然而,这种推论注定要失败,因为C 只出现在非推论的上下文中。 IE。两个模板中的类型(对于该特定对)至少不像其他模板中的类型那样专门化——这反过来意味着没有一个模板比另一个模板更专门化。

正如@T.C. 所指出的,CWG #1391 的分辨率会有所帮助。特别是这部分:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    但是,海事组织。这不应该工作,因为我认为,草案说,编译器不会考虑 C::InputDataMap -

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 2021-07-26
      • 2018-05-10
      • 1970-01-01
      相关资源
      最近更新 更多