Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Program runs in Visual Studio 2012 but not ideone.com

I have a gut-feeling VS2012 is wrong on this one, but I'm not certain.

After looking this question, I felt like trying to implement something similar.

My version works fine on Visual Studio 2012, but does not 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 a few 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's the driver:

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

    return 0 ;
}

Ideone is complaining about template deductions and its unable to find the correct operator>> candidate function:

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 correct? If Ideone is correct, is there any easy fix to this code?

like image 525
jliv902 Avatar asked Oct 07 '14 20:10

jliv902


People also ask

Why is my program not running in VS Code?

If your terminal is set to run as administrator only, and you are not launching VS Code as administrator, the terminal will not be able to open. You can either change the default terminal or edit the properties of the terminal exe to not run as administrator.

How do you run a code on VS community?

Build and run your code in Visual Studio To build your project, choose Build Solution from the Build menu. The Output window shows the results of the build process. To run the code, on the menu bar, choose Debug, Start without debugging. A console window opens and then runs your app.

How do I run a Visual Studio code in release mode?

In Solution Explorer, right-click the project and choose Properties. In the side pane, choose Build (or Compile in Visual Basic). In the Configuration list at the top, choose Debug or Release. Select the Advanced button (or the Advanced Compile Options button in Visual Basic).


2 Answers

Ideone (actually, GCC) is correct here. In Visual Studio, it compiles because of an infamous extension which allows temporaries to bind to non-const lvalue references (the standard forbids that).

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

One, don't use temporaries for the 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 of std::move), and use that:

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 an overload of operator >> taking an r-value reference:

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'd provide mixed &, && and &&, & overloads as well.

like image 134
Angew is no longer proud of SO Avatar answered Oct 16 '22 09:10

Angew is no longer proud of SO


The first template basically fails because you can't bind a prvalue temporary - IntSquare () - to a non-const lvalue reference.

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

This says that you can't initialize Pipe<int, int>& with a prvalue of type IntSquare. The value category is unfortunately not explicitly mentioned in the error message. Although this is a standard rule VC++ ignores it to ease (or troublesome) a C++-programmers daily life.

The second template

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

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

like image 38
Columbo Avatar answered Oct 16 '22 08:10

Columbo