The program works in Visual Studio 2012, but not ideone.com

I have a gut feeling of VS2012, this is wrong, but I'm not sure.

After looking at this question , I wanted to implement something similar.

My version works fine on Visual Studio 2012, but it doesn't even compile on Ideone .

Here is my main interface:

#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 ; } 

Here are some test classes:

 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 ; } }; 

And here is the driver:

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

Ideone complains about template deductions and cannot find the correct candidate function operator>> :

 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 ; 

Which compiler is right? If Ideone is correct, is there any easy fix for this code?

+6
source share
2 answers

The ideal (actually GCC) is true here. In Visual Studio, it compiles due to the notorious extension that allows temporary links to non-constant lvalue references (the standard prohibits this).

I see several possible ways to solve this problem in standard C ++:

First, do not use time series for pipeline stages:

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

Two, create a β€œstay” function (opposite std::move ) and use this:

 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 ; } 

Three, provide operator >> overloading using the r-value link:

 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! } 

Of course, ideally, you would suggest mixed overloads of &, && and &&, & .

+2
source

The first template basically fails because you cannot bind the temporary IntSquare () - IntSquare () -. Prior to the non-constant Lvalue reference

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

This suggests that you cannot initialize Pipe<int, int>& with a prvalue of type IntSquare . Unfortunately, the error message does not mention the category of values. Although this is a standard rule, VC ++ ignores it to make it easier (or more difficult) for the daily life of C ++ programmers.

Second pattern

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

fails because for two different Out outputs, two different types were deduced - the first of them int (for lhs ) and the second IntSquare .

+2
source

Source: https://habr.com/ru/post/976383/


All Articles