2012-04-12 14 views
6

Ich habe das Spiel mit C++ 11 in letzter Zeit, und kam mit der folgenden Summenfunktion auf:Compiler warnt nicht vor Präzisionsverlust?

template <typename T> 
inline T sum(const std::function<T (int)> &f, int initial, int end) 
{ 
    T retval = 0; 
    for(int k = initial; k <= end; k++) { 
     retval += f(k); 
    } 
    return retval; 
} 

Die Idee ist, dass ich eine Lambda-Funktion übergeben kann und somit eine saubere und gut lesbare Funktion für mathematische Summen. Ich habe dann versucht, die folgenden:

int main() 
{ 
    std::array<double, 2> arr1 = {{ 0.5, 1.5 }}, 
          arr2 = {{ 1.5, -0.5 }}; 
    auto n = sum<int>([&](int k) { return arr1[k]*arr2[k]; }, // Precision loss! 
         0, 1); 
    return 0; 
} 

ich kompiliert diese mit g ++ 4.6.3: g++ -Wall -pedantic -std=c++0x -o test main.cpp und geben keine Warnung über den Genauigkeitsverlust ich im Kommentar des Quellcodes bemerkt.

Es ist ziemlich wahrscheinlich, dass sum<int> eine schlechte Sache zu tun ist, aber es ist vielleicht nicht so offensichtlich in komplexeren Kontexten. Sollte der Compiler nicht bemerken, dass der Rückgabewert meiner Lambda-Funktion double ist, und mich warnen, dass ich beim Gießen an int die Präzision verliere? Gibt es einen bestimmten Grund, warum nicht?

+1

Die Funktion wird von der Präzision nicht darüber im Klaren sein becasue die Laufzeit eine implizite Umwandlung tut, bevor ihr die Argumente. Sie haben jedoch Recht, in einer idealen Welt sollten Sie zumindest eine Warnung im Visual Studio/Ihrer IDE sehen, um zu reflektieren, dass dies zu einem Präzisionsverlust führen würde. Aber ist es nicht so etwas, worum es bei Komponententests geht? – War

+0

@Wardy in einer idealen Welt würde es nicht kompilieren (d. H. Es wäre ein Fehler, keine Warnung) ohne eine explizite Anfrage, diesen Präzisionsverlust zu verursachen. –

+0

ok ... auch einen C# Entwickler im, und ich habe die Regeln von .net gehen (nicht sicher, ob Sie auch einen .net-Compiler verwenden, aber) heißt es in der Dokumentation, dass, wenn eine weniger genaue Art ein implizite erwartet wird Cast wird angewendet ... es wird als Merkmal der Sprache betrachtet. Ich stimme dir zu ... ein Fehler wäre der absolute Traum in deinem Szenario, aber meiner Erfahrung nach nicht die Plattform. – War

Antwort

5

Scheint völlig in Ordnung. Sie sagen dem Compiler, dass er sich nicht mit Template Argument Deduction (d. H. sum<double>) beschäftigen soll, sondern sagen Sie ihm explizit, dass er sum<int> verwenden soll. Das ist so gut wie eine explizite Besetzung.

[Bearbeiten] Was ist

template <typename F> 
auto sum(F const& f, int initial, int end) -> decltype(f(initial)) 
{ 
    auto retval = f(initial++); 
    while(initial <= end) { 
     retval += f(initial++); 
    } 
    return retval; 
} 
+0

Es ist seltsam genug, wenn Warnungen Aussagen in der Funktion über _implementation_ auf einem darauf hinweisen, _wie_ abhängen, in der Template-Argumente – user396672

+0

@ user396672 abgeleitet worden: Welche Funktion „Implementierung“ werden Sie beziehen? Es gibt keine Aussage in 'Summe (const std :: Funktion & f, ...)', die eine Warnung garantiert. – MSalters

+0

return (implizite Umwandlung in int) arr1 [k] * arr2 [k]; – user396672

2

VS11 hat eine Warnung aus:

Warnung 1 Warnung C4189: 'n': lokale Variable initialisiert wird, aber nicht
Warnung 2 Warnung C4244 verwiesen: '+ =': Umwandlung von 'double' in 'int', möglicher Datenverlust

Bearbeiten, eigentlich ist diese Warnung von der Verwendung des Codes:

Sie erhalten eine andere Warnung über die schlechte Konvertierung, wenn Sie std::function<T (int)> verwenden, also VS ist immer noch gut in diesem Problem. (IMO, sollten Sie Funktoren in der Regel als ein Template-Typ statt st :: function nehmen)

Sogar klingelt mit -Weything keine Warnung darüber (Edit: obwohl ich die Std :: -Funktion nicht testen kann Version mit Clang ATM). Scheint wie etwas, das verbessert werden könnte.

ich tun, obwohl diese seltsame Warnung erhalten:

ConsoleApplication1.cpp:15:51: warning: will never be executed [-Wunreachable-code] 
    auto n = sum<int>([&](int k) { return arr1[k]*arr2[k]; }, // Precision loss! 
                ^~~~ 
1

Wenn Sie die Funktors Fixierung aufheben, und wenn Sie die Zeile retval += f(k); in der folgenden Art und Weise zu retval += T { f(k) }; ändern:

// Machinery to allow caller to indifferently use 
// sum(f, i, j) and sum<R>(f, i, j) 
struct deduced {}; 

template< 
    typename Request = deduced 
    , typename Functor 
    , typename Ret = typename std::conditional< 
     std::is_same<Request, deduced>::value 
     , typename std::result_of<Functor&(int)>::type 
     , Request 
    >::type 
> 
inline Ret sum(Functor f, int initial, int end) 
{ 
    Ret retval = 0; 
    for(int k = initial; k <= end; k++) { 
     retval += Ret { f(k) }; 
    } 
    return retval; 
} 

dann anstatt sich auf Die Bereitschaft des Compilers zu warnen, machen Sie es erforderlich, um eine Diagnose als eine eingrenzende Konvertierung ist innerhalb der Liste-Initialisierung (dh Initialisierung mit geschweiften Klammern) verweigert.

Ich glaube nicht, dass es eine zuverlässige Möglichkeit gibt, wenn Sie den Funktor auf eine std::function<Sig> beschränken. Das hängt ausschließlich davon ab, wie die Implementierung std::function geschrieben hat, wann Warnungen für das Einschränken von Konvertierungen ausgegeben werden und ob sie sogar für ihren eigenen Code warnt.

Verwandte Themen