przekierowanie strumieni.

0
#include <iostream>
#include <fstream>

using namespace std;

int main(int argc, char* argv[]) {


    (argc > 2 ? ofstream(argv[2], ios::out | ios::binary )  : cout )
    <<
    (argc > 1 ? ifstream(argv[1], ios::in | ios::binary ) : cin ).rdbuf();


    return 0;
}

Co w tym kodzie jest nie tak, że rzuca błędem?

1

ofstream(argv[2], ios::out | ios::binary) ma tu typ const ofstream&

   ifstream fin;
   ofstream fout;
   if(argc>1)
     {
      fin.open(argv[1]);
      fatal(!fin,"Nie da sie otworzyc podanego pliku wejscia");
      cin.rdbuf(fin.rdbuf());
     }
   if(argc>2)
     {
      fout.open(argv[2]);
      fatal(!fin,"Nie da sie stworzyc podanego pliku wyjscia");
      cout.rdbuf(fout.rdbuf());
     }
0

to jak poprawić mój kod?

5

Nie wiem czy da się to zrobić w prosty sposób. (da się, użyć basic_Xstream::rdbuf, za przykładem @_13th_Dragon​a)

Co w tym kodzie jest nie tak, że rzuca błędem?

Nie jestem 100% pewien tego co piszę, ale to wydaje mi się sensowne.
Jak działa operator ternarny, a konkretniej, jak jest ustalony jego wynikowy typ? To jest opisane dokładniej w § 5.16 [expr.cond]/3:

N3797 napisał(a)

if the second and third operand have different types and either has (possibly cv-qualified) class type, or if both are glvalues of the same value category and the same type except for cv-qualification, an attempt is made to convert each of those operands to the type of the other. The process for determining whether an operand expression E1 of type T1 can be converted to match an operand expression E2 of type T2 is defined as follows:
— If E2 is an lvalue: E1 can be converted to match E2 if E1 can be implicitly converted (Clause 4) to the type “lvalue reference to T2”, subject to the constraint that in the conversion the reference must bind directly (8.5.3) to an lvalue.
— If E2 is an xvalue: E1 can be converted to match E2 if E1 can be implicitly converted to the type “rvalue reference to T2”, subject to the constraint that the reference must bind directly.
— If E2 is a prvalue or if neither of the conversions above can be done and at least one of the operands has (possibly cv-qualified) class type:
— if E1 and E2 have class type, and the underlying class types are the same or one is a base class of the other: E1 can be converted to match E2 if the class of T2 is the same type as, or a base class of, the class of T1, and the cv-qualification of T2 is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification of T1. If the conversion is applied, E1 is changed to a prvalue of type T2 by copy-initializing a temporary of type T2 from E1 and using that temporary as the converted operand.
— Otherwise (i.e., if E1 or E2 has a nonclass type, or if they both have class types but the underlying classes are not either the same or one a base class of the other): E1 can be converted to match E2 if E1 can be implicitly converted to the type that expression E2 would have if E2 were converted to a prvalue (or the type it has, if E2 is a prvalue).

ostream(argv[2]) to prvalue, a cin to lvalue. Kompilator próbuje przekonwertować jedno w drugie, ale nie może, bo basic_ostream jest niekopiowalny, a konstruktor przenoszący jest protected.

Możesz to obejść w ohydny sposób z leakami: http://melpon.org/wandbox/permlink/Wkezq9jg7layMydV

#include <iostream>
#include <fstream>
 
using namespace std;
 
int main(int argc, char* argv[])
{
    ostream& o = argc > 2 ? *new ofstream(argv[2], ios::out | ios::binary )  : cout;
    istream& i = argc > 1 ? *new ifstream(argv[1], ios::in | ios::binary ) : cin;
    
    o << i.rdbuf();
 
    return 0;
}

co potem możesz upięknić¹ do: http://melpon.org/wandbox/permlink/199NAbuuc42g4IAI

#include <iostream>
#include <fstream>
#include <memory>
 
using namespace std;
 
int main(int argc, char* argv[])
{
    auto o = argc > 2 ? make_shared<ofstream>(argv[2], ios::out | ios::binary )  : shared_ptr<ostream>(&cout,[](void*){});
    auto i = argc > 1 ? make_shared<ifstream>(argv[1], ios::in | ios::binary ) : shared_ptr<istream>(&cin,[](void*){});
    
    *o << i->rdbuf();
 
    return 0;
}

Swoją drogą ostatnio robiłem coś podobnego w D i tam to się odbyło bez problemów:

auto inFile = args.length > 2 ? File(args[2], a == Action.Decode ? "r" : "rb") : stdin;
auto outFile = args.length > 3 ? File(args[3], a == Action.Decode ? "wb" : "w") : stdout;

¹ dla pewnych definicji piękna.

1

Właściwie to już pokazałem ale widzę że nawet @kq tego nie zauważył :D
Może być dwa warianty:
1.

   cout.rdbuf(argc>2?ofstream(argv[2],ios::out|ios::binary).rdbuf():cout.rdbuf());
   cin.rdbuf(argc>1?ifstream(argv[1],ios::in|ios::binary).rdbuf():cin.rdbuf());
   cout<<cin.rdbuf();
   cout.rdbuf(argc>2?ofstream(argv[2],ios::out|ios::binary).rdbuf():cout.rdbuf());
   cout<<(argc>1?ifstream(argv[1],ios::in|ios::binary).rdbuf():cin.rdbuf());
0

prvalue to coś o czymś nie wiem czy tylko literówka?
Wiem co to rvalue i lvalue, ale co to jest Prvalue? I tak samo Plvalue?

0

basic_ostream jest niekopiowalny

Co to dokładniej znaczy? Konstruktor kopiujący jest sprywatyzowany :D ?

1

To nie jest literówka: http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues

niekopiowalny: http://en.cppreference.com/w/cpp/io/basic_ostream/basic_ostream Przeładowanie (2) - = delete oznacza celowy brak implementacji danej funkcji. Nie ma jej i nie można jej używać.

0

rozumiem, że w C++03 jak nie chcieliśmy umożliwiać używania metody to prywatyzowaliśmy ją- nie było innej możliwości. Skądinąd nie było to najlepsze rozwiązanie.
W C++11 wprowadzili taką możliwość, żeby określić, których metod celowo nie chcemy. Problem dotyczy tylko takich metod, które są domyślnie? Np. właśnie domyślny konstruktor kopiujący? No bo jeżeli nie chcemy czegoś to normalnie nie definiujemy tego :D
Dobrze myślę?

3

@mielony: Możesz usunąć (= delete) każdą funkcję. Nawet "zwykłe" funkcje - tzn. nie będące składnikami klas. To może się przydać, kiedy chcesz zabronić niejawnej konwersji argumentów:

void funkcja_dla_double(float arg) = delete;
void funkcja_dla_double(double arg) {
...
}

funkcja_dla_double(1.0f); // błąd kompilacji

Taką funkcję można wywołać tylko dla argumentu o typie double.

0

ok, inaczej by zaszzła niejawna konwersja?
Czy nie jest tak, że C++ zaczyna gonić swój ogon?
Zamiast powiedzieć co chcemy to musimy jeszcze informować czego nie chcemy. Trochę to dziwne.

0

Nie jest dziwne, zobacz przykład od @Endrju, akurat jest dziwne że nie chcemy mieć możliwości przekazania float.

1 użytkowników online, w tym zalogowanych: 0, gości: 1