简体   繁体   中英

GCC 4.9 ambiguous overload template specialization

I'm running into an issue with gcc 4.9.2 (with -std=c++11) not compiling a piece of code with the error message being

call of overloaded 'InsertDataIntoInputMap(int&, boost::shared_ptr&)' is ambiguous

The code does compile with 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);
}

while the following does actually compile with both gcc and 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;
}

I would have thought that the compiler should take the function with the boost::shared_ptr argument in both cases?

This problem can be reduced to an imprecision in partial ordering: Pairs in which no template-parameters appear that are involved in deduction are still considered and compaired. That issue was addressed by CWG #455 and #885 as well.

In your example, overload resolution isn't able to distinguish the overloads. Hence partial ordering is necessary. And partial ordering will try to perform deduction twice, with the parameter type P being typename C::InputDataMap::key_type .
However, that deduction is doomed to fail, since C solely appears in a non-deduced context. Ie the type from both templates (for that particular pair) is not at least as specialized as the type from the respective other template - and that, in turn, implies that neither of the templates is more specialized than the other.

As noted by @TC, the resolution of CWG #1391 helps. This part in particular:

Change 14.8.2.4 [temp.deduct.partial] paragraph 4 as follows:

Each type nominated above from the parameter template and the corresponding type from the argument template are used as the types of P and A . If a particular P contains no template-parameters that participate in template argument deduction, that P is not used to determine the ordering.

Now, the first parameter pair is entirely ignored in both ways (as the types of C are solely determined from the explicit argument list), and the second overload is found to be more specialized.

A simple alias can make that code work:

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

But imo. this shouldn't work, cause I thought, the draft says, the compiler will not consider the C::InputDataMap - Namespace in

class F = typename C::InputDataMap::key_type

and F will be a non-deduced context (like key_type).

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