2015-07-22 13 views
16

ich mit gcc 4.9.2 in ein Problem laufen (mit -std = C++ 11) nicht ein Stück Code mit der Fehlermeldung Kompilierung wirdGCC 4.9 mehrdeutig Überlastung Template-Spezialisierung

Aufruf überladener ‚InsertDataIntoInputMap (int & boost :: shared_ptr &)‘mehrdeutig ist

Der Code mit msvc 2013 nicht kompilieren

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

während die folgende ist tatsächlich sowohl mit gcc und msvc kompiliert:

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

Ich hätte gedacht, dass der Compiler die Funktion mit dem boost :: shared_ptr Argumente in beiden Fällen nehmen soll?

+0

Coliru kompiliert das erste Beispiel mit clang und g ++ nicht. http://coliru.stacked-crooked.com/a/d1035dd01513af3a – NathanOliver

+1

Ich denke, es hat etwas damit zu tun, dass 'C :: InputDataMap :: key_type' ein nicht-abgeleiteter Kontext ist, aber meine manuelle Ausführung von Template-Deduktion und Bestellung ist nicht gut genug, um dies durchzuarbeiten. – TartanLlama

+2

Ich beginne zu denken, dass Clang und GCC hier falsch sind, da die zweite Template-Funktion mindestens so spezialisiert für einen Parameter und spezialisierter für den anderen ist, also unabhängig von nicht-abgeleiteten Kontexten ausgewählt werden sollte. Kann jemand eine bessere Erklärung liefern? – TartanLlama

Antwort

3

Dieses Problem kann auf eine Ungenauigkeit bei der partiellen Sortierung reduziert werden: Paare, in denen keine Template-Parameter erscheinen, die an der Ableitung beteiligt sind, werden immer noch berücksichtigt und verglichen. Dieses Problem wurde auch von CWG #455 und #885 angesprochen.

In Ihrem Beispiel kann die Überladungsauflösung die Überlastungen nicht unterscheiden. Daher ist eine teilweise Anordnung erforderlich. Bei einer Teilbestellung wird versucht, den Abzug zweimal durchzuführen, wobei der Parameter Ptypename C::InputDataMap::key_type ist.
Dieser Abzug ist jedoch zum Scheitern verurteilt, da C nur in einem nicht abgeleiteten Kontext erscheint. I.e. Der Typ aus beiden Vorlagen (für dieses bestimmte Paar) ist nicht mindestens so spezialisiert wie der Typ aus der jeweils anderen Vorlage - und das wiederum bedeutet, dass keine der Vorlagen spezialisierter ist als die andere.

Wie von @ T.C. festgestellt, hilft die Auflösung von CWG #1391. Dieser Teil insbesondere:

ändern 14.8.2.4 [temp.deduct.partial] Absatz 4 wie folgt:

Jeder Typ oben vom Parametervorlage und den entsprechenden Typ aus dem Argument Vorlage nominiert verwendet als die Typen P und A. Wenn ein bestimmter P keine Template-Parameter enthält, die an der Ableitung von Template-Argumenten beteiligt sind, wird P nicht verwendet, um die Reihenfolge zu bestimmen.

Nun wird das erste Parameterpaar wird in beiden Richtungen (wie die Arten von C sind allein aus der expliziten Argumentliste bestimmt) völlig ignoriert, und die zweite Überlast festgestellt wird speziellere sein.

1

Ein einfacher Alias ​​kann, dass Code funktioniert:

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

aber imo. sollte dies nicht funktionieren, weil ich dachte, so der Entwurf, wird der Compiler nicht die C betrachtet :: InputDataMap - Namespace in

class F = typename C::InputDataMap::key_type 

und F wird ein nicht-abgeleitete Kontext (wie key_type) sein.

Verwandte Themen