Let’s say you have few functions:
func_1(arg1, arg2, arg3) ,
func_2 (arg1, arg2) and
func_3 (arg1, arg2, arg3).
All 3 performing similar steps:
func (arg1, arg2, arg3)
{
Read line from the file
validate_func()
Store results into arg3
}
So my question is – what would best way to approach this in order to combine these 3 functions into 1?
My thoughts to approach this problem to use function with variable number of arguments (va_start, va_end) . What i’m not sure how to approach is to call appropriate validation function – will it be possible to use in this case function pointer as one of the arguments?Not sure at this point
Any suggestions, links, examples are welcome
Thanks

>>what would best way to approach this in order to combine these 3 functions into 1?

The best way to do this is to not do it. Functions are there to help create more readability for the coder and the reader. The more the better. By trying to combine
functions into 1, you are sacrificing readability and usefulness for a little performance if any. Why do you even want to do this. Maybe if you tell us more about
your program, then we can help make it faster. I'm sure you have other bottlenecks.
Plus I doubt it will give any performance boost. It might save a few calls, and stop
some level of indirection, but thats nothing in this era of computing.

Thanks for replay
Allow me to ask this question – at what point you’ll say : ok, it is too mach of those functions, let’s put them together. How many? Let’s say you have 10 functions doing exactly same thing but rules of the evaluation, which are 3 lines of code. Would you do look at the possibilities to find some solution to combine as much as possible into one solution/function
Regards,

Then that means you need to abstract the problem. Create 1 common function, that
does a common functionality that each of the other function does, and inside the other function, call that common function.

Very simplified example, this is just to demonstrate what I mean nothing more

#include "stdafx.h"
#include "vector"
#include "list"
#include "map"
#include "fstream"

using namespace std;

void ReadFile_FillStruct_1(string _fileName, vector<string>& _vectorStorage, bool _boolArg);
void ReadFile_FillStruct_2(string _fileName, vector<int>& _vectorStorage);
void ReadFile_FillStruct_3(string _fileName, list<string>& _listStorage, bool _boolArg);
void ReadFile_FillStruct_4(string _fileName, map<int, string>& _mapStorage, bool _boolArg);

int _tmain(int argc, _TCHAR* argv[])
{
    vector<string> _vector_1;
    vector<int> _vector_2;
    list<string> _list;
    map <int,string> _map;
    string _fileName = "C:\\Temp\\FileName.txt";
    ReadFile_FillStruct_1(_fileName, _vector_1, false);

    _fileName = "C:\\Temp\\FileName1.txt";
    ReadFile_FillStruct_3(_fileName, _list, true);

    _fileName = "C:\\Temp\\FileName2.txt";
    ReadFile_FillStruct_2(_fileName, _vector_2);

    _fileName = "C:\\Temp\\FileName3.txt";
    ReadFile_FillStruct_4(_fileName, _map, false);
	return 0;
}

void ReadFile_FillStruct_1(string _fileName, vector<string>& _vectorStorage, bool _boolArg)
{
	ifstream infile;
    infile.open (_fileName.c_str());
    while(!infile.eof()) 
    {
    // parse data, check if it is meaningful(same for all func)******
    // perform necessary munipulation/validation based on _boolArg
    // fill the container
    }
	infile.close();
}

void ReadFile_FillStruct_2(string _fileName, vector<int>& _vectorStorage)
{
    ifstream infile;
    infile.open (_fileName.c_str());
    while(!infile.eof()) 
    {
    // parse data, check if it is meaningful(same for all func)******
    // fill the container
    }
	infile.close();
}

void ReadFile_FillStruct_3(string _fileName, list<string>& _listStorage, bool _boolArg)
{
    ifstream infile;
    infile.open (_fileName.c_str());
    while(!infile.eof()) 
    {
    // parse data, check if it is meaningful(same for all func)******
    // perform necessary munipulation based on _boolArg
    // fill the container
    }
	infile.close();
}

void ReadFile_FillStruct_4(string _fileName, map<int, string>& _mapStorage, bool _boolArg)
{	
    ifstream infile;
    infile.open (_fileName.c_str());
    while(!infile.eof()) 
    {
    // parse data, check if it is meaningful(same for all func)******
    // perform necessary munipulation based on _boolArg
    // fill the container
    }
	infile.close();
}

Regards,

You need to abstract when possible. So in the example you gave, create a prase
function and call it on each function.

template<typename ReturnType, typename InputType>
ReturnType void prase(const InputType& in){
 /* do praising here */
 /* and return whatever you need to return */
}

Edited 6 Years Ago by firstPerson: n/a

As suggested by firstPerson, class or function templates are typically the best way to achieve common functionality for different types. So you can look up templates for info on that.

Also, operator or function overloading can make the code more uniform (as in the above, your functions don't need to have different names). Take the "ostream" class of the C++ std libraries for example, overloading of the operator << for all types makes all writing (or output) operations of any type look exactly the same (i.e. cout << int_var << double_var << custom_object << "literal string or flag ->" << endl).

Combining the above two concepts should solve your problem very nicely.

I started some reading on implementation you suggested, seems that this is the way to solve this. One more question I still would like to ask, as you could see in the short example current functions are with different numbers of arguments. I could use overload, is there any other(s) way?
Thanks

1. overloading with different number of arguments is fine, it works very well.
2. function templates will also do it well (although it boils down to overloading at the end, but just less code, if used properly).
3. consider default argument values (which allow you to call one function with different number of arguments, given that some can be defaulted), another form of overloading, for a function where there is one or more parameters that often don't matter (i.e. have a default value) like from your code:

void ReadFile_FillStruct_1(string _fileName, vector<string>& _vectorStorage, bool _boolArg = false); //notice the = false (default value), in the prototype only, not in the definition

4. consider wrapping the arguments in another class or struct or union (look up tuples) as templates or not.


From the looks of your code example, I get the feeling that you are implementing a "serialization" library. If you are comfortable with templates, or if you are willing to get comfortable with them, consider look at this almost-standard library, at least for inspiration. I would not recommend you look at it before being comfortable with template meta-programming, because of risk of head explosions!

Edited 6 Years Ago by mike_2000_17: n/a

This article has been dead for over six months. Start a new discussion instead.