2016-11-02 8 views
1

Ich weiß, dass es ein ziemlich allgemeiner Titel ist, aber ich habe etwas Code und es erscheint mir so komisch, dass es nicht kompilieren kann.Warum kann dieser Code nicht kompiliert werden?

Here ist eine Demo des Problems. Wenn Sie scalar_t von double zu float ändern, kompiliert der Code fein. Warum kann float hier verdoppelt werden? wenn Sie die Konstanten double s (1.0) oder int s (1) ändern auch sie kippen werden in der Tat gefördert. Ist das nicht die Art von Sache, die nur funktionieren sollte?

Vollcodebeispiel:

#include <valarray> 
#include <numeric> 
#include <iterator> 
#include <iostream> 

template<typename T> 
T sigmoid(const T &in) 
{ 
    return 1.f/(1.f + std::exp(-in)); 
} 

template<typename T> 
T logit(const T &in) 
{ 
    return std::log(in/(1.f - in)); 
} 

using scalar_t = double; 

int main(int argc, char **argv) 
{ 
    std::valarray<scalar_t> f = { 0.1f, 0.3f, 0.5f, 0.9f }; 

    scalar_t alpha = 0.5f; 
    scalar_t beta = -1.f; 

    auto lC = logit(f);  
    std::valarray<scalar_t> skC = alpha * lC + beta; 
    auto sC = sigmoid(skC); 

    std::copy(std::begin(sC), std::end(sC), std::ostream_iterator<scalar_t>(std::cout, " ")); 
    std::cout << std::endl; 

    scalar_t num = 0.7f; 
    auto lS = logit(num); 
    auto sS = sigmoid(alpha * lS + beta); 

    std::cout << sS << std::endl; 

    return 0; 
} 
+0

Förderung ist nicht das Problem. 'valarray's' operator-'leitet den gleichen Typ für die linke Seite (' T const & ') und die rechte Seite (' valarray const & ') ab. Es ist widersprüchlich, weil es für dasselbe Template-Argument sowohl "float" als auch "double" erhält. Sie sollten es beheben können, indem Sie '1.0'. – 0x499602D2

+0

"Warum kann float hier nicht befördert werden?" Auf welchen bestimmten Punkt in Ihrem Code beziehen Sie sich als "hier"? Von welcher Promotion sprichst du? – AnT

+0

@ 0x499602D2 Sie haben recht, aber warum sollte hier keine implizite Konvertierung stattfinden? Ich kann es nicht wirklich beheben, indem ich 1 mache.0 weil ich kein Vorwissen von 'scalar_t 'habe (oder davon ausgehe, dass ich das nicht tue) –

Antwort

4

Die operator - Sie verwenden ist definiert als

template <class T> std::valarray<T> operator- (const T& val, const std::valarray<T>& rhs); 

Diese mess, dass es val die gleiche Art wie die Elemente in der valarray werden erwartet. Da Sie eine float verwenden, wenn Abzug Template-Argument geschieht sieht es, dass val ein float ist aber rhs hat einen Elementtyp double. Da diese Typen nicht übereinstimmen, schlägt die Deduktion fehl, und Sie erhalten einen Compilerfehler. Beachten Sie, dass während der Ableitung von Vorlagenargumenten keine Conversions auftreten.

+0

"keine Konvertierungen passieren während der Vorlage Argument Abzug" Ich denke, ist das Problem. Die offensichtliche nächste Frage ist also, wie kann ich es beheben, vorausgesetzt, ich weiß nichts über "scalar_t"? Auch warum sollten implizite Konvertierungen in diesem Szenario nicht zulässig sein? –

+0

@MaxEhrlich Am einfachsten wäre es, die Literale in 'scalar_t's umzuwandeln. Wenn die Funktion nur für Standardtypen verwendet wird, können Sie immer das Member "value_type" verwenden und die Literale auf diesen Typ umwandeln. – NathanOliver

+0

Das würde es für dieses Beispiel lösen, aber ich nehme an, ich habe keine Vorkenntnisse von 'scalar_t' und keine Kenntnis vom Typ von' T' (wie Sie sehen können, habe ich es in der gleichen Weise wie 'skalar_t' benutzt sowie eine 'valarray ' die beide gut funktionieren sollten bis auf die fehlende implizite Konvertierung) –

1

Dies brachte eine ziemlich interessante Diskussion darüber, wie Agnostiker Vorlagen Konstanten in dieser Art zu verwenden. Überraschenderweise scheint es eine Antwort zu geben. Untersucht man die sigmoid Funktion, sehen wir, dass sie auch float Konstanten mit einem valarray<double> verwendet, aber keinen Compiler-Fehler aufweist. Dies liegt daran, die std::exp(-in) Linie die valarray<double> zu einem Ausdruck Vorlage wandelt die die Standard-Bibliothek verwendet, um die Berechnung zu optimieren, und aus welchem ​​Grunde sie kümmert sich nicht um float oder double (zum Beispiel bieten sie die Überlastung). So ist die Lösung kam ich mit war ein unärer Operator + zum logit Funktion hinzuzufügen, die nichts tut absolut außer den valarray<double> zu einem Ausdruck Vorlage zu konvertieren, die mit dem float konstant arbeiten können.

Here ist das Update Codebeispiel

und die neue logit Funktion wie diese

template<typename T> 
T logit(const T &in) 
{ 
    return std::log(in/(1.f - (+in))); 
} 

Hinweis der unäre Operator + (+in)

Auch sieht beachten Sie, dass NathanOliver die akzeptierte Lösung die Frage beantwortet, wie gefragt

Verwandte Themen