Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GCC 4.9 ambiguous overload template specialization

Tags:

c++

gcc

c++11

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?

like image 550
tt293 Avatar asked Jul 22 '15 12:07

tt293


2 Answers

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. I.e. 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 @T.C., 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.

like image 157
Columbo Avatar answered Sep 22 '22 00:09

Columbo


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).

like image 37
JulianH Avatar answered Sep 22 '22 00:09

JulianH