2014-10-07 8 views
6

Ich habe ein Bauchgefühl VS2012 ist falsch in diesem einen, aber ich bin mir nicht sicher.Programm läuft in Visual Studio 2012 aber nicht ideone.com

Nachdem ich this question gesucht hatte, wollte ich etwas Ähnliches implementieren.

Meine Version funktioniert gut in Visual Studio 2012, aber kompiliert nicht unter Ideone.

Hier ist meine Haupt-Schnittstelle:

#include <iostream> 
#include <string> 

template <class In, class Out> 
struct Pipe 
{ 
    typedef In in_type ; 
    typedef Out out_type ; 

    In in_val ; 

    Pipe (const in_type &in_val = in_type()) : in_val (in_val) 
    { 
    } 

    virtual auto operator()() const -> out_type 
    { 
     return out_type() ; 
    } 
}; 

template <class In, class Out, class Out2> 
auto operator>> (const Pipe <In, Out> &lhs, Pipe <Out, Out2> &rhs) -> Pipe <Out, Out2>& 
{ 
    rhs = lhs() ; 
    return rhs ; 
} 

template <class In, class Out> 
auto operator>> (const Pipe <In, Out> &lhs, Out &rhs) -> Out& 
{ 
    rhs = lhs() ; 
    return rhs ; 
} 

Hier sind ein paar Testklassen:

struct StringToInt : public Pipe <std::string, int> 
{ 
    StringToInt (const std::string &s = "") : Pipe <in_type, out_type> (s) 
    { 
    } 

    auto operator()() const -> out_type 
    { 
     return std::stoi (in_val) ; 
    } 
}; 

struct IntSquare : public Pipe <int, int> 
{ 
    IntSquare (int n = 0) : Pipe <in_type, out_type> (n) 
    { 
    } 

    auto operator()() const -> out_type 
    { 
     return in_val * in_val ; 
    } 
}; 

struct DivideBy42F : public Pipe <int, float> 
{ 
    DivideBy42F (int n = 0) : Pipe <in_type, out_type> (n) 
    { 
    } 

    auto operator()() const -> out_type 
    { 
     return static_cast <float> (in_val)/42.0f ; 
    } 
}; 

Und hier ist der Fahrer:

int main() 
{ 
    float out = 0 ; 
    StringToInt ("42") >> IntSquare() >> DivideBy42F() >> out ; 
    std::cout << out << "\n" ; 

    return 0 ; 
} 

Ideone über Vorlage Abzüge beschwert und es ist nicht in der Lage, die korrekte operator>> Kandidatenfunktion zu finden:

prog.cpp: In function ‘int main()’: 
prog.cpp:75:21: error: no match for ‘operator>>’ (operand types are ‘StringToInt’ and ‘IntSquare’) 
    StringToInt ("42") >> IntSquare() >> DivideBy42F() >> out ; 
        ^
prog.cpp:75:21: note: candidates are: 
prog.cpp:23:6: note: Pipe<Out, Out2>& operator>>(const Pipe<In, Out>&, Pipe<Out, Out2>&) [with In = std::basic_string<char>; Out = int; Out2 = int] 
auto operator>> (const Pipe <In, Out> &lhs, Pipe <Out, Out2> &rhs) -> Pipe <Out, Out2>& 
    ^
prog.cpp:23:6: note: no known conversion for argument 2 from ‘IntSquare’ to ‘Pipe<int, int>&’ 
prog.cpp:30:6: note: template<class In, class Out> Out& operator>>(const Pipe<In, Out>&, Out&) 
auto operator>> (const Pipe <In, Out> &lhs, Out &rhs) -> Out& 
    ^
prog.cpp:30:6: note: template argument deduction/substitution failed: 
prog.cpp:75:35: note: deduced conflicting types for parameter ‘Out’ (‘int’ and ‘IntSquare’) 
    StringToInt ("42") >> IntSquare() >> DivideBy42F() >> out ; 

Welcher Compiler ist korrekt? Wenn Ideone korrekt ist, gibt es eine einfache Lösung für diesen Code?

+3

Bezug zu (* vielleicht duplizieren *?): [? Nicht konstanter Verweis auf temporäres, Visual Studio Bug gebunden] (http://stackoverflow.com/q/16380966/1708801) ... im Grunde ist gcc hier richtig . Wenn Sie in Visual Studio mit '/ Za' bauen, wird es auch fehlschlagen, [siehe live] (http://rextester.com/GYMOJ23021). –

+3

Es ist dumm zu stimmen, um diese Frage zu schließen. * Warum funktioniert dieser Code nicht *. Der Test könnte kleiner sein, aber es ist ein vollständiger Testfall mit widersprüchlichen Ergebnissen zwischen Compilern und es ist definitiv nicht offensichtlich für die meisten, was korrekt ist. –

Antwort

2

Ideone (eigentlich, GCC) ist hier richtig. In Visual Studio kompiliert es wegen einer berüchtigten Erweiterung, die es ermöglicht, dass Provisorien an nicht-konstante lvalue-Referenzen binden (der Standard verbietet das).

Ich sehe mehr Möglichkeiten, diese in Standard-C zu lösen ++:

One, nicht Provisorien für die Pipeline-Stufen verwenden:

int main() 
{ 
    float out = 0 ; 
    StringToInt stage1("42"); 
    IntSquare stage2; 
    DivideBy24F stage3; 
    stage1 >> stage2 >> stage3 >> out ; 
    std::cout << out << "\n" ; 

    return 0 ; 
} 

Zwei, erstellen Sie eine "Aufenthalt" Funktion (gegenüber std::move), und verwenden, die:

template <class T> 
T& stay(T &&x) { return x; } 

int main() 
{ 
    float out = 0 ; 
    stay(StringToInt ("42")) >> stay(IntSquare()) >> stay(DivideBy42F()) >> out ; 
    std::cout << out << "\n" ; 

    return 0 ; 
} 

Drei bieten eine Überlastung von operator >> unter einer r-Wert Referenz:

template <class In, class Out, class Out2> 
auto operator>> (const Pipe <In, Out> &&lhs, Pipe <Out, Out2> &&rhs) -> Pipe <Out, Out2>& 
{ 
    return lhs >> rhs; // Notice that lhs and rhs are lvalues! 
} 

Natürlich würden Sie im Idealfall auch gemischte &, && und &&, & Überladungen zur Verfügung stellen.

2

Die erste Vorlage schlägt grundsätzlich fehl, weil Sie einen prvalue temporären - IntSquare() - nicht an eine nicht konstante lvalue-Referenz binden können.

no known conversion for argument 2 from ‘IntSquare’ to ‘Pipe<int, int>&’ 

Dies sagt, dass Sie nicht Pipe<int, int>& mit einem prvalue vom Typ IntSquare initialisieren. Die Wertkategorie wird in der Fehlermeldung leider nicht explizit erwähnt. Obwohl dies eine Standardregel ist, ignoriert VC++ es, um das tägliche Leben eines C++ - Programmierers zu erleichtern (oder zu stören).

Die zweite Vorlage

template <class In, class Out> 
auto operator>> (const Pipe <In, Out> &lhs, Out &rhs) -> Out& 
{ 
    rhs = lhs() ; 
    return rhs ; 
} 

schlägt fehl, da für zwei verschiedene Abzüge von Out zwei unterschiedliche Typen abgeleitet wurden - die erste sein int (für lhs) und die zweite IntSquare zu sein.

+0

+1 Ich fand beide Antworten hilfreich, aber ich ging mit dem anderen. – jliv902

Verwandte Themen