2017-09-12 3 views
1

Clang und GCC (mit Ausnahme von MSVC) können ein Vorlagenargument nicht auflösen, wenn es als Argument für die Vorlagenfunktion std::addressof<int> übergeben wird. Das Folgende ist ein Beispiel für einen solchen Fehler:Warum kann das Template-Argument nicht von std :: addressof <int> aufgelöst werden?

std::vector<int> v{1,2,3,4,5}; 
std::vector<int*> pv(iv.size()); 
std::transform(v.begin(), v.end(), pv.begin(), std::addressof<int>); 

Clang:

<source>:8:5: error: no matching function for call to 'transform' 
    std::transform(iv.begin(), iv.end(), piv.begin(), std::addressof<int>); 
    ^~~~~~~~~~~~~~ 
/opt/compiler-explorer/clang-5.0.0/bin/../include/c++/v1/algorithm:2028:1: note: candidate template ignored: couldn't infer template argument '_UnaryOperation' 
transform(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _UnaryOperation __op) 
^ 

GCC:

/opt/compiler-explorer/gcc-7.2.0/include/c++/7.2.0/bits/stl_algo.h:4295:5: note: template argument deduction/substitution failed: 
<source>:8:74: note: could not resolve address from overloaded function 'addressof<int>' 
    std::transform(iv.begin(), iv.end(), piv.begin(), std::addressof<int>); 
                     ^

Dieser Fehler würde Sinn machen, wenn das Argument war stattdessen ein std::addressof, weil die UnaryOperator Template-Parameter wäre mehrdeutig. Allerdings muss der Compiler nicht ableiten, was T ist in std::addressof<int>, würde ich hier keine Zweideutigkeit.

Hier ist ein funktionierendes Beispiel für meine Erwartungen (auf Clang kompiliert 5 und GCC 7.2):

template <typename T> 
T* addrof(T& a) 
{ 
    return __builtin_addressof(a); 
} 

template <typename F, typename T> 
void foo(F f, T& a) 
{ 
    f(a); 
} 

int main() 
{ 
    int a = 42; 
    foo(addrof<int>, a); 
} 

Mein Zweifel ist: Warum kann Template-Argument von std::addressof<int> abgeleitet werden nicht std::transform s?

Antwort

5

Ja, es funktioniert nicht in Ihrem Beispiel, weil es zwei Überladungen für jede Vorlage std::addressof da C++ 17 (eine immer die Adresse und eine gelöschte Version, die einen rvalue Bezug nimmt), und es ist nicht eindeutig für den Compiler, eine zu wählen. Einfachste Lösung ist Lambda zu verwenden:

#include <vector> 
#include <algorithm> 

void foo() { 
    std::vector<int> v{1,2,3,4,5}; 
    std::vector<int*> pv(v.size()); 
    std::transform(v.begin(), v.end(), pv.begin(), 
        [](int& i) { return std::addressof(i);}); 
} 

Diese Überlastungen sind hier aufgeführt: http://en.cppreference.com/w/cpp/memory/addressof

Die andere Option ist Guss zu verwenden, aber es ist nur hässlich, und Thy Sollte Lambdas bevorzugen Dennoch wird für Vollständigkeit sorgen:

#include <vector> 
#include <algorithm> 

void foo() { 
    std::vector<int> v{1,2,3,4,5}; 
    std::vector<int*> pv(v.size()); 

    std::transform(v.begin(), v.end(), pv.begin(), 
        static_cast<int* (*)(int&) >(std::addressof<int>)); 
} 
+0

Wissen Sie, welcher Vorschlag das geändert hat? –

+2

http://wg21.link/lwg2598 – Brian

Verwandte Themen