c++ - Substitutionsfehler mit `std:: function` und zuvor abgeleiteten Template-Parametern-warum?




c++11 templates (2)

Betrachten Sie den folgenden Code:

template <typename> 
struct S { };

void g(S<int> t);

template <typename T>
void f(T, std::function<void(S<T>)>);

Beim Versuch aufzurufen

f(0, g);

Ich erhalte folgenden Fehler:

error: no matching function for call to 'f'
    f(0, g);
    ^

note: candidate template ignored: could not match 
      'function<void (S<type-parameter-0-0>)>' 
      against 'void (*)(S<int>)'
void f(T, std::function<void(S<T>)>);
     ^

Live-Beispiel auf godbolt.org

Ich verstehe zwar, dass der Typ des Parameters std::function Allgemeinen nicht abgeleitet werden kann, da es sich um einen nicht abgeleiteten Kontext handelt

In diesem Fall kann T zuerst durch das übergebene Argument 0 und dann durch std::function<void(S<T>)> , um std::function<void(S<int>)> .

Ich würde erwarten, dass der Compiler nach Ableitung von T=int T überall in der Signatur einsetzen und dann versuchen würde, den Parameter std::function mit dem Argument g zu konstruieren.

Warum ist das nicht der Fall? Ich gehe davon aus, dass die Reihenfolge, in der die Ersetzung / der Abzug erfolgt, etwas damit zu tun hat, aber ich würde gerne den entsprechenden Standardtext sehen.

Bonusfrage: Könnte dies möglicherweise in einem zukünftigen Standard geändert werden, während die Abwärtskompatibilität erhalten bleibt, oder gibt es einen fundamentalen Grund, warum diese Art der Substitution nicht funktioniert?


Ich verstehe zwar, dass der Typ des Parameters std :: function im Allgemeinen nicht abgeleitet werden kann, da es sich um einen nicht abgeleiteten Kontext handelt

Es ist kein nicht hergeleiteter Kontext. Ganz im Gegenteil. Da versucht wird, für den Parameter von std::funcition einen Abzug std::funcition , das Argument jedoch keine std::function , schlägt der Abzug fehl. Der Abzug von Template-Argumenten von Funktionsargumenten muss für alle Funktionsargumente übereinstimmen. Wenn es für einen fehlschlägt, schlägt es vollständig fehl.

[temp.deduct.type]

2 In einigen Fällen erfolgt der Abzug unter Verwendung eines einzelnen Satzes von Typen P und A. In anderen Fällen erfolgt der Abzug unabhängig für jedes P / A-Paar und der Abzug Die Werte der Vorlagenargumente werden dann kombiniert. Wenn für ein P / A-Paar keine Typableitung möglich ist oder wenn für ein Paar die Ableitung zu mehr als einem möglichen Satz von abgeleiteten Werten führt oder wenn unterschiedliche Paare unterschiedliche abgeleitete Werte ergeben oder wenn ein Template-Argument weder abgeleitet noch explizit bleibt angegeben, schlägt der Abzug von Vorlagenargumenten fehl.

Indem man den Typ des zweiten Funktionsparameters in einen nicht deduzierten Kontext setzt, kann man den Fehler tatsächlich überwinden:

#include <functional>

template<typename T>
struct type_identity {
    using type = T;
};

template <typename> 
struct S { };

void g(S<int> ) {}

template <typename T>
void f(T, typename type_identity<std::function<void(S<T>)>>::type) {}

int main() {
    f(0, g);
}

T wird erfolgreich aus dem ersten Funktionsargument abgeleitet, und es ist nichts mehr zu schließen. Der Abzug wird also als Erfolg gewertet.

Live


Obwohl ich verstehe, dass der Typ des Parameters std::function Allgemeinen nicht abgeleitet werden kann, da es sich um einen nicht abgeleiteten Kontext handelt, kann T in diesem Fall zunächst durch das übergebene Argument 0 .

Das ist nicht wahr. T ist in diesem Zusammenhang ableitbar. Wenn Sie den Code in ändern

template <typename T>
void f(std::function<void(S<T>)>);

int main()
{
    f(std::function<void(S<int>)>(g));
}

Der Code würde kompiliert und T wird korrekt abgeleitet.

Ihr Problem ist, dass Sie ein Objekt an die Funktion übergeben, aus der T nicht extrahiert werden kann. Der Compiler führt keine Konvertierung der Funktionsargumente durch, wenn er versucht, T abzuleiten. Das heißt, Sie haben ein int und eine Funktion als die Typen, die an die Funktion übergeben werden. Er erhält int von 0 und versucht dann, den Typ von der std::function Sie im zweiten Parameter übergeben haben. Da Sie jedoch keine std::function haben, kann er T nicht extrahieren. Aus diesem Grund erhalten Sie eine Error.





template-deduction