Skip to main content
edited body
Source Link
Oliver Schönrock
  • 2.5k
  • 1
  • 10
  • 23

The common idiom usefor making objects "printable" in C++ is to implement the << operator. This is best done using a friend function inside the class as shown.

The common idiom use making objects "printable" in C++ is to implement the << operator. This is best done using a friend function inside the class as shown.

The common idiom for making objects "printable" in C++ is to implement the << operator. This is best done using a friend function inside the class as shown.

explain more about std::optional
Source Link
Oliver Schönrock
  • 2.5k
  • 1
  • 10
  • 23

Note how in main() I call get_config_unit() assign it to maybe_unit (a common idiom to use maybe_*) then check for the -> bool conversion in the same if statement parens. This is using the C++17 if statement "init-statement". Then I "dereference" the std::optional<config_unit> maybe_unit using the * operator.

This all makes for very terse syntax and stops variables and the "maybeness" leaking out.

##Use of exceptions

#include <functional><fstream>
#include <iostream><functional>
#include <fstream><iostream>
#include <sstream>
#include <string>
#include <vector>

struct config_unit {
  std::string parameter;
  std::string value;

  friend std::ostream& operator<<(std::ostream& ostream, const config_unit& cu) {
    return ostream << "Parameter: '" << cu.parameter << "'\t"
                   << "Value: '" << cu.value << "'" << '\n';
  }
};

std::optional<config_unit> get_config_unit(const std::string& line) {
  std::istringstream       ss(line);
  std::string              field;
  std::vector<std::string> fields;
  while (getline(ss, field, ' ')) fields.push_back(field);
  if (fields.size() != 2) return std::nullopt;
  return config_unit{fields[0], fields[1]};
}

int main() {
  std::string   filename{"music.txt"};
  std::ifstream fstream(filename);
  if (fstream.fail()) {
    std::cerr << "couldn't open file '" << filename << "\n";
    return EXIT_FAILURE;
  }
  std::string line;
  while (std::getline(fstream, line)) {
    if (auto maybe_unit = get_config_unit(line); maybe_unit) {
    if (maybe_unit) std::cout << *maybe_unit;
    }
  }
  return EXIT_SUCCESS;
}

##Use of exceptions

#include <functional>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

struct config_unit {
  std::string parameter;
  std::string value;

  friend std::ostream& operator<<(std::ostream& ostream, const config_unit& cu) {
    return ostream << "Parameter: '" << cu.parameter << "'\t"
                   << "Value: '" << cu.value << "'" << '\n';
  }
};

std::optional<config_unit> get_config_unit(const std::string& line) {
  std::istringstream       ss(line);
  std::string              field;
  std::vector<std::string> fields;
  while (getline(ss, field, ' ')) fields.push_back(field);
  if (fields.size() != 2) return std::nullopt;
  return config_unit{fields[0], fields[1]};
}

int main() {
  std::string filename{"music.txt"};
  std::ifstream fstream(filename);
  if (fstream.fail()) {
    std::cerr << "couldn't open file '" << filename << "\n";
    return EXIT_FAILURE;
  }
  std::string line;
  while (std::getline(fstream, line)) {
    auto maybe_unit = get_config_unit(line);
    if (maybe_unit) std::cout << *maybe_unit;
  }
  return EXIT_SUCCESS;
}

Note how in main() I call get_config_unit() assign it to maybe_unit (a common idiom to use maybe_*) then check for the -> bool conversion in the same if statement parens. This is using the C++17 if statement "init-statement". Then I "dereference" the std::optional<config_unit> maybe_unit using the * operator.

This all makes for very terse syntax and stops variables and the "maybeness" leaking out.

##Use of exceptions

#include <fstream>
#include <functional>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

struct config_unit {
  std::string parameter;
  std::string value;

  friend std::ostream& operator<<(std::ostream& ostream, const config_unit& cu) {
    return ostream << "Parameter: '" << cu.parameter << "'\t"
                   << "Value: '" << cu.value << "'" << '\n';
  }
};

std::optional<config_unit> get_config_unit(const std::string& line) {
  std::istringstream       ss(line);
  std::string              field;
  std::vector<std::string> fields;
  while (getline(ss, field, ' ')) fields.push_back(field);
  if (fields.size() != 2) return std::nullopt;
  return config_unit{fields[0], fields[1]};
}

int main() {
  std::string   filename{"music.txt"};
  std::ifstream fstream(filename);
  if (fstream.fail()) {
    std::cerr << "couldn't open file '" << filename << "\n";
    return EXIT_FAILURE;
  }
  std::string line;
  while (std::getline(fstream, line)) {
    if (auto maybe_unit = get_config_unit(line); maybe_unit) {
      std::cout << *maybe_unit;
    }
  }
  return EXIT_SUCCESS;
}

added 2 characters in body
Source Link
Oliver Schönrock
  • 2.5k
  • 1
  • 10
  • 23

In case of parsing failures, you were previously returning an empty"empty" ConfigUnit (correct term is value initialized). I have shown a, probably cleaner alternative, using C++17 std::optional.


 
#include <functional>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

struct config_unit {
  std::string parameter;
  std::string value;

  friend std::ostream& operator<<(std::ostream& ostream, const config_unit& cu) {
    return ostream << "Parameter: '" << cu.parameter << "'\t"
                   << "Value: '" << cu.value << "'" << '\n';
  }
};

std::optional<config_unit> get_config_unit(const std::string& line) {
  std::istringstream       ss(line);
  std::string              field;
  std::vector<std::string> fields;
  while (getline(ss, field, ' ')) fields.push_back(field);
  if (fields.size() != 2) return std::nullopt;
  return config_unit{fields[0], fields[1]};
}

int main() {
  std::string filename{"music.txt"};
  std::ifstream fstream(filename, std::ios_base::in);
  if (fstream.fail()) {
    std::cerr << "couldn't open file '" << filename << "\n";
    return EXIT_FAILURE;
  }
  std::string line;
  while (std::getline(fstream, line)) {
    auto maybe_unit = get_config_unit(line);
    if (maybe_unit) std::cout << *maybe_unit;
  }
  return EXIT_SUCCESS;
}

In case of parsing failures, you were previously returning an empty ConfigUnit. I have shown a, probably cleaner alternative, using C++17 std::optional.


 
#include <functional>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

struct config_unit {
  std::string parameter;
  std::string value;

  friend std::ostream& operator<<(std::ostream& ostream, const config_unit& cu) {
    return ostream << "Parameter: '" << cu.parameter << "'\t"
                   << "Value: '" << cu.value << "'" << '\n';
  }
};

std::optional<config_unit> get_config_unit(const std::string& line) {
  std::istringstream       ss(line);
  std::string              field;
  std::vector<std::string> fields;
  while (getline(ss, field, ' ')) fields.push_back(field);
  if (fields.size() != 2) return std::nullopt;
  return config_unit{fields[0], fields[1]};
}

int main() {
  std::string filename{"music.txt"};
  std::ifstream fstream(filename, std::ios_base::in);
  if (fstream.fail()) {
    std::cerr << "couldn't open file '" << filename << "\n";
    return EXIT_FAILURE;
  }
  std::string line;
  while (std::getline(fstream, line)) {
    auto maybe_unit = get_config_unit(line);
    if (maybe_unit) std::cout << *maybe_unit;
  }
  return EXIT_SUCCESS;
}

In case of parsing failures, you were previously returning an "empty" ConfigUnit (correct term is value initialized). I have shown a, probably cleaner alternative, using C++17 std::optional.

#include <functional>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

struct config_unit {
  std::string parameter;
  std::string value;

  friend std::ostream& operator<<(std::ostream& ostream, const config_unit& cu) {
    return ostream << "Parameter: '" << cu.parameter << "'\t"
                   << "Value: '" << cu.value << "'" << '\n';
  }
};

std::optional<config_unit> get_config_unit(const std::string& line) {
  std::istringstream       ss(line);
  std::string              field;
  std::vector<std::string> fields;
  while (getline(ss, field, ' ')) fields.push_back(field);
  if (fields.size() != 2) return std::nullopt;
  return config_unit{fields[0], fields[1]};
}

int main() {
  std::string filename{"music.txt"};
  std::ifstream fstream(filename);
  if (fstream.fail()) {
    std::cerr << "couldn't open file '" << filename << "\n";
    return EXIT_FAILURE;
  }
  std::string line;
  while (std::getline(fstream, line)) {
    auto maybe_unit = get_config_unit(line);
    if (maybe_unit) std::cout << *maybe_unit;
  }
  return EXIT_SUCCESS;
}

added 5 characters in body
Source Link
Toby Speight
  • 88.4k
  • 14
  • 104
  • 327
Loading
added 2 characters in body
Source Link
Oliver Schönrock
  • 2.5k
  • 1
  • 10
  • 23
Loading
Use real headers; fixed spelling and grammar
Source Link
Toby Speight
  • 88.4k
  • 14
  • 104
  • 327
Loading
added 50 characters in body
Source Link
Oliver Schönrock
  • 2.5k
  • 1
  • 10
  • 23
Loading
added 50 characters in body
Source Link
Oliver Schönrock
  • 2.5k
  • 1
  • 10
  • 23
Loading
added 50 characters in body
Source Link
Oliver Schönrock
  • 2.5k
  • 1
  • 10
  • 23
Loading
Source Link
Oliver Schönrock
  • 2.5k
  • 1
  • 10
  • 23
Loading