C++ copy_if lambda capturing std::string - c++

This is a follow up question from here: C++ - Developing own version of std::count_if?
I have the following function:
// vector for storing the file names that contains sound
std::vector<std::string> FilesContainingSound;
void ContainsSound(const std::unique_ptr<Signal>& s)
{
// Open the Wav file
Wav waveFile = Wav("Samples/" + s->filename_);
// Copy the signal that contains the sufficient energy
std::copy_if(waveFile.Signal().begin(), waveFile.Signal().end(),
FilesContainingSound.begin(), [] (const Signal& s) {
// If the energy bin > threshold then store the
// file name inside FilesContaining
}
}
But to me, I only need to capture the string "filename" inside of the lambda expression, because I'll only be working with this. I just need access to the waveFile.Signal() in order to do the analysis.
Anyone have any suggestions?
EDIT:
std::vector<std::string> FilesContainingSound;
std::copy_if(w.Signal().begin(), w.Signal().end(),
FilesContainingSound.begin(), [&] (const std::unique_ptr<Signal>& file) {
// If the energy bin > threshold then store the
// file name inside FilesContaining
});

You seem to be getting different levels of abstraction confused here. If you're going to work with file names, then you basically want something on this order:
std::vector<std::string> input_files;
std::vector<std::string> files_that_contain_sound;
bool file_contains_sound(std::string const &filename) {
Wav waveFile = Wav("Samples/" + filename);
return binned_energy_greater(waveFile, threshold);
}
std::copy_if(input_files.begin(), input_files.end(),
std::back_inserter(files_that_contain_sound),
file_contains_sound);
For the moment I've put the file_contains_sound in a separate function simply to make its type clear -- since you're dealing with file names, it must take a file name as a string, and return a bool indicating whether that file name is one of the group you want in your result set.
In reality, you almost never really want to implement that as an actual function though--you usually want it to be an object of some class that overloads operator() (and a lambda is an easy way to generate a class like that). The type involved must remain the same though: it still needs to take a file name (string) as a parameter, and return a bool to indicate whether that file name is one you want in your result set. Everything dealing with what's inside the file will happen inside of that function (or something it calls).

Related

How to read data from a file from within a function

I want to make my code more efficient, specifically the reading of data from a text file. Here is a snapshot of what it looks like now:
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)));
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)));
... // and so on
Basically, the read_value function creates an ifstream object, opens the file, reads one line of data, and closes the file connection. This happens many times. What I want to do is to open the file once, read every line that is needed into the struct, and then close the file connection.
Here is the creating values struct function with parameters:
static values create_struct(std::string name, std::map<std::string, int> mapping) {
values V(name);
V.population = read_value(find_line_number(name, find_in_map(pop, mapping)), file);
V.net_growth = read_value(find_line_number(name, find_in_map(ngr, mapping)), file);
// more values here
return V;
}
The function that calls create_struct is shown below:
void initialize_data(string name) {
// read the appropriate data from file into a struct
value_container = Utility::create_struct(name, this->mapping);
}
I am thinking of instead defining the ifstream object in the function initialize_data. Given what is shown about my program, would that be the best location to create the file object, open the connection, read the values, then close the connection? Also, would I need to pass in the ifstream object into the create_values struct, and if so, by value, reference or pointer?
The short answer is to create your ifstream object first and pass it as reference to your parser. Remember to seek the stream back to the beginning before you leave your function, or when you start to read.
The RAII thing to do would be to create a wrapper object that automatically does this when it goes out of scope.
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::ifstream& mStream;
}
Then you create a wrapper instance when entering a method that will read the fstream.
void read_value(std::ifstream& input, ...){
ifStreamRef autoRewind(input);
}
Or, since the Ctor can do the conversion...
void read_value(ifStreamRef streamRef, ...) {
streamRef.mStream.getLine(...);
}
std::ifstream itself follows RAII, so it will close() the stream for you when your stream goes out of scope.
The long answer is that you should read up on dependency injection. Don't create dependencies inside of objects/functions that can be shared. There are lots of videos and documents on dependency injection and dependency inversion.
Basically, construct the objects that your objects depend on and pass them in as parameters.
The injection now relies on the interface of the objects that you pass in. So if you change your ifStreamRef class to act as an interface:
class ifStreamRef{
ifStreamRef(std::ifstream& _in) : mStream(_in){}
~ifStreamRef(){mStream.seekg(0);}
std::string getLine(){
// todo : mStream.getLine() + return "" on error;
}
bool eof() { return mStream.eof(); }
std::ifstream& mStream;
}
Then later on you can change the internal implementation that would take a reference to vector<string>& instead of ifstream...
class ifStreamRef{
ifStreamRef(std::vector<string>& _in) : mStream(_in), mCursor(0){}
~ifStreamRef(){}
std::string getLine(){
// todo : mStream[mCursor++] + return "" on error;
}
bool eof() { return mCursor >= mStream.size(); }
std::vector<string>& mStream;
size_t mCursor;
}
I have oversimplified a few things.

How do I load custom "const" variables from a config file in C++?

I currently have a function which loads variables from a config file. It uses these to initialise a set of constant config variables.
// header file
namespace cfg {
extern const char *config_value;
}
// source file
namespace cfg {
const char *config_value;
}
bool load_config() {
cfg::config_value = load_config_line("config_value");
}
const char *load_config_line(const char *key) {
// read value from config.cfg...
}
This works pretty well. The problem is that now I want to reuse this code in several other projects, which means the constant values have to change. This means changing the config_value names in four different places each in the code. It also means I have several copies of essentially the same code to maintain in different projects.
Is there a way of setting different sets of constant values using the same code for the reading and parsing? Perhaps so that all I have to do is change the header file and it automatically finds those value names in the config file? The tricky part is that ideally the outward facing config values themselves should be constant and available at compile time (using a string to value map for example is undesirable, as I would prefer to have the compile time protection).
The solution here is to not use global variables, and instead have some settings struct which you explicitly initialize with values loaded from the file. The struct instance itself doesn't need to be const (you'll need to be able to load the values into it, unless you pass everything in on construction), but all access to it should be const. This last bit can be achieved by passing settings as e.g. a const settings& to wherever it is needed.
int main()
{
// Variant A: 2-step init
settings s;
s.loadConfigFile(filename);
// Variant B: 1-step init - can make instance itself const
const settings s(filename);
Thing worker(s); // Thing::Thing(const settings&)
worker.work();
}
Of course Worker can be anything your heart desires.
Note that settings itself needs no special constness whatsoever:
struct settings
{
std::string config_value;
}
It is the external const that guards access to the values contained within.

C++ Pass variable of unknown name to method

Is there a way in c++ to pass to a method a variable where that variable could be one of several different variables (of same type) depending on where the method is called.
For example:
A method to check if a file exists with the correct name.
At one point in the program, I might want to check a users file exists, so the user enters their username into string variable username, and that is passed to CheckFile:
bool LotterySystem::CheckFile(const std::string &USERNAME)
{
//if file exists, return false, else return true
FILE *fin = fopen((USERNAME + ".txt").c_str(), "r");
if (fin)
{
fclose(fin);
return false;
}
return true;
}
At another point I might want to check a file with stock information exists, so the user enters the stock they wish to check into string variable stockType:
bool LotterySystem::CheckFile(const std::string &STOCKTYPE)
{
//if file exists, return false, else return true
FILE *fin = fopen((STOCKTYPE + ".txt").c_str(), "r");
if (fin)
{
fclose(fin);
return false;
}
return true;
}
Is there a way to pass a generic string variable with any name, to CheckFile, without having to have different CheckFile methods for every file name to be checked?
You don't need differnt CheckFile methods. In fact, having more than one would result in a multiple definition error, because you are defining two methods with the same signature.
Just call it with different arguments:
LotterySystem ls;
ls.CheckFile("MyNameIsFred");
ls.CheckFile("MyPreferredPreferredStockName");
It seems like you want to pass different values of type const std::string, which in C++ can be passed simply using a single function. You will have to change the value which you are calling the function, not create different instances of the bool LotterySystem::CheckFile method.
And also, no compiler would compile the two instances of the same function, with same parameters.
bool LotterySystem::CheckFile(const std::string &USERNAME)
{
//if file exists, return false, else return true
FILE *fin = fopen((USERNAME + ".txt").c_str(), "r");
if (fin)
{
fclose(fin);
return false;
}
return true;
}
Then call:
LotterySystem mySystem;
std::string sName = "John Doe", sStockName = "ZXY";
bool nameFileExists = mySystem.CheckFile(sName);
bool stockFileExists = mySystem.CheckFile(sStockName);
It seems like you want to alter the semantics of the function by changing the name in the signature. That's not how it works. As chris states in the comments, the function's semantics stay the same, no matter what string you pass - only the return value will change, depending on what functions used in CheckFile return. Giving the string a different name does not create another overload of CheckFile and will not, in any way, alter the semantics or code flow within the function.
What you want is a dedicated function per purpose. CheckFile should just do what the name suggests(well, sort of): check whether the txt file denoted by the string you pass exists.
Layered on CheckFile you might want to implement additional functionality for the purpose of checking different types of files. That being said, if you're dealing with text-files, you need to parse and validate the contents anyway to be sure you actually have a valid user file or a stock-info file. In essence, you want something like this:
bool IsUserFile(const std::string&); // validates text-file contents
bool processUserFile(const std::string& path) // path omitting the extension '.txt'
{
if(!(CheckFile(path) && IsUserFile(path)))
return false;
// open file process contents
// return true if successful, false otherwise
}
Similarly for stock-info files.
On another note, there is no need to make such a function a member function of LotterySystem and if you insist on making it a member function, consider making it a static member function - it doesn't depend on an instance of LotterySystem.
Also, if I understand your intentions correctly, you want to check if a file exists. So, your CheckFile function needs to return true if it can open the file. Currently, it does exactly the opposite. Leave a comment if I'm mistaken.
Please note: checking for the existence of a file only by seeing if your application can open it is a very restricted case. It might exist and fopen() might still not be able to open it, be it due to insufficient privileges or other conditions.

a simple way to read configuration properties

I am trying to add few configurable properties to an existing code/project. I found it is really annoyance to have so many steps to do this:
add entry to the configuration file;
declare a key string in the h file;
define that key string in the cpp file;
declare a getXXX method/function in the h file;
define that getXXX method/function in the cpp file;
In our case, that header file and cpp file are only for properties read from text file and those properties are only needed inside this module. So we may be able to simplify them with less files or less steps. Any idea/suggestion?
EDIT:
A map is used to hold contents from the text file.
A sample get method likes this:
unsigned int Module1Config::getSleepTime()
{
return getPropertyMap().getUnsignedIntProperty(SLEEP_TIME_KEY);
}
What about a private std::map whose keys are just those declared in the configuration file. Then, you can have a getter function that gets the value typed as you need it, with a default value if it does not exist:
template<class T>
T get(const std::string &key) const
{
if the key is in the map,
return its value converted to type T
else
return T();
}
You may find useful a second function to tells you if some key is declared:
bool exists(const std::string &key) const
{
return true iif key is in the map
}
The pros of this approach is that you don't need to modify the class when new properties are added. The con is that key names are not created as constant identifiers in your h file, so you have to use strings all the time, which may be error prone. Anyway, I think its versatility is worth it (this is the method I use in my programs).

boost test case for function taking user input

I have a function that takes in user input via std::cin:
std::getline(std::cin, in);
and creates a corresponding data structure by matching it with a regular expression. The function then returns this data structure.
I'm using boost.test and I want to create a unit test to check that the output data type is correct given some inputs. However I don't know how to go about it since the input isn't passed as an argument to the function.
EDIT: Is there a simple way to create a boost test case that feeds the function a string via standard input?
If you have access to the source code of the function that calls std::getline, then the easiest solution is to rewrite it as a wrapper of another function having the same signature and implementation, but taking an additional std::istream& parameter that is used in place of std::cin. For example, if you currently have:
my_struct my_func()
{
//...
std::getline(std::cin, in);
//...
}
Then rewrite like this:
my_struct my_func(std::istream& is);
inline my_struct my_func()
{
return my_func(std::cin);
}
my_struct my_func(std::istream& is)
{
//...
std::getline(is, in);
//...
}
This way, you will be able to test the core functionality of my_func on constructed input sequences by passing std::istringstream objects into my_func(std::istream&).
If you do not have access to the source code of the function that calls std::getline, then one trick that you can use is to replace the standard in descriptor. See this answer for code that replaces the standard out descriptor and modify accordingly.