7
\$\begingroup\$

The following function (function template rather) is to take a vector of any type and write it a file using a filestream object.

template<class T>
void Vec_WriteFile(const vector<T>& vec, ifstream file, char del = '\n')
{
   for (const T& element : vec) file << element << del;
   file << "\b ";
}

This function is very straightforward and simple; however, I'm a student to C++ and would love to learn different ways of doing even the simplest of tasks.

\$\endgroup\$
2
  • \$\begingroup\$ Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. \$\endgroup\$
    – Peilonrayz
    Commented Mar 6, 2017 at 13:08
  • \$\begingroup\$ allow me to change the indentation. that was a mistake i made when i created the post. Not an original code error. \$\endgroup\$
    – Ethan
    Commented Mar 6, 2017 at 18:28

1 Answer 1

5
\$\begingroup\$

You need to include the headers your code depends on; don't assume that the user of your code will include them for you:

#include <vector>
#include <ostream>  // see note below

Never require your user to bring names into the current namespace; type names used in your public interface should always be qualified:

template<class T>
void Vec_WriteFile(const std::vector<T>& vec, std::ifstream file, char del = '\n')

Don't attempt to write to an istream. Your output should go to an ostream instead. You could use an ofstream, but that's quite specific. Instead, you should accept a reference to any ostream; the user can then pass an ofstream or std::cout or any other output stream:

template<class T>
void Vec_WriteFile(const std::vector<T>& vec, std::ostream& file, char del = '\n')

There's nothing in your code that wouldn't work for a std::list equally as well as for a std::vector, so you can be more general:

template<class Container>
void Vec_WriteFile(const Container& vec, std::ostream& file, char del = '\n')

Naming: del evokes "delete" in my head before I reset and think "delimiter". It might be better written in full, or perhaps as sep for "separator".


Layout: at first glance, it's not obvious which code is controlled by the for condition, as you have inconsistent indentation.


Writing a backspace over the final delimiter isn't the same as not writing the delimiter. If you want the delimiter between items but not after the final item, the usual way is to track whether the loop is in its first iteration:

bool first = true;
for (...) {
    if (first)
        first = false;
    else
        file << del;
    file << element;
}

Error reporting: instead of just assuming that the writes are all successful, we could report via the return value from the function. This may help the user remember to deal with errors, which could be overlooked if they have to check the stream state after the call.


My version:

#include <ostream>

template<class Container>
std::ostream& write_container(const Container& c,
                     std::ostream& out,
                     char delimiter = '\n')
{
    bool write_sep = false;
    for (const auto& e: c) {
        if (write_sep)
            out << delimiter;
        else
            write_sep = true;
        out << e;
    }
    return out;
}
\$\endgroup\$
9
  • \$\begingroup\$ Thank you. That iftstream was a bug on my part. Meant it to be ofstream. I just learned templates two days ago, so I'm still learning how general you can be. Thank you very much, learned more than you can know from your answer. \$\endgroup\$
    – Ethan
    Commented Mar 6, 2017 at 12:47
  • \$\begingroup\$ Maybe I didn't understand you correctly, but wouldn't it be better to avoid this in-loop if and just write the first element before the loop? (yes, foreach is far more fancy, but it is a code - not always as beautiful as we wanted it to be) \$\endgroup\$
    – Shmuel H.
    Commented Mar 6, 2017 at 20:05
  • \$\begingroup\$ what if container is empty? I tend to think the foreach with if checks will accomplish it better \$\endgroup\$
    – Ethan
    Commented Mar 6, 2017 at 22:18
  • \$\begingroup\$ May want to fix your return type as you are returning from std::ostream& to bool. No conversion exists. \$\endgroup\$
    – Snowhawk
    Commented Mar 6, 2017 at 23:56
  • \$\begingroup\$ @Snowhawk: before operator bool() was added in C++11, operator void*() served that purpose. Do you get an error with the above? If so, which compiler and/or Standard Library implementation? \$\endgroup\$ Commented Mar 7, 2017 at 8:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.