I am writing an app to parse lines in a text file. The problem is that I need to be able to load different routines depending on a variable set at run-time. I can not change the format of the incoming file.
int intFormat = 1; //Loaded from INI file
void __fastcall TForm1::Button1Click(TObject *Sender) {
myFileConverstion *myFC;
switch(intFormat) {
case 1:
myFC = new FileConverstionCompanyA();
case 2:
myFC = new FileConverstionCompanyB();
}
myFileConverstion->Execute("fileName");
}
Within ->Execute(), I would be calling private (or protected) methods to do the parsing. There are some of the methods that could be used across all formats, too.
What would be the best OOP way to do this?
Create a virtual object i.e: myFileConverstion? Then inherit from that for the CompanyA, B, C, etc.
write myFileConverstion with all the common methods (private/protected) and a virtual Execute(). Then just change the Execute() internals for the various "companies"?
I'm looking for some guidance.
Haven't really tried anything yet, I'm in the planning stage.
There would also be the possibility to realize the whole thing with std:.function by inserting them into some kind of lookup map. Here is some example:
#include <functional>
#include <iostream>
#include <unordered_map>
class FileConverter
{
using convert_engine_t = std::function< bool( const std::string& ) >;
std::unordered_map< size_t, convert_engine_t > engines;
convert_engine_t *activeEngine { nullptr };
public:
template < class T >
auto addEngine( size_t id, T && routine ) -> void
{
engines.emplace( id, std::forward< T >( routine ) );
}
auto setActiveEngine( size_t id ) -> bool
{
const auto iterFound = engines.find( id );
if ( iterFound == engines.end() )
return false;
activeEngine = &iterFound->second;
return true;
}
auto convert( const std::string fileName ) -> bool
{
if ( !activeEngine || !( *activeEngine ) )
return false;
return ( *activeEngine )( fileName );
}
};
int main()
{
struct MyConvertingEngineA
{
auto operator()( const auto& fn ) {
std::cout << "Doing A" << std::endl; return true;
}
};
auto myConvertingEngineB = []( const auto& fn ) {
std::cout << "Doing B" << std::endl; return true;
};
FileConverter myFC;
myFC.addEngine( 1, MyConvertingEngineA() );
myFC.addEngine( 2, std::move( myConvertingEngineB ) );
myFC.addEngine( 8, []( const auto& fn ){ std::cout << "Doing C" << std::endl; return true; } );
myFC.setActiveEngine( 1 );
myFC.convert( "MyFileA1" );
myFC.convert( "MyFileA2" );
myFC.setActiveEngine( 2 );
myFC.convert( "MyFileB" );
myFC.setActiveEngine( 8 );
myFC.convert( "MyFileC" );
myFC.setActiveEngine( 7 ); // Will fail, old engine will remain active
return 0;
}
Output:
Doing A
Doing A
Doing B
Doing C
A few explanations about the code:
The addEngine function uses templates with a forwarding reference and
perfect forwarding to provide the widest possible interface.
Engines are copied or moved here, depending on the type of reference passing. The engines are passed in form of "callable objects".
Different types like functors or lambdas can be added.
Even (as in the example) generic lambdas can be passed (auto parameter) as long as the function signature of of std::function is fulfilled.
This saves another redundant specification of the string type.
If you have large and complex engines, use a separate class instead of a lambda to keep the local scope small
Shared parser-functionality could also be passed to the respective engines via smart pointer if you don't want to have any inheritance.
class EngineA
{
std::shared_ptr< ParserCore > parserCore;
public:
EngineA( std::shared_ptr< ParserCore > parserCoreParam ) :
parserCore( std::move( parserCoreParam ) )
{}
auto operator()( const auto& fn ) {
std::cout << "Doing A" << std::endl; return true;
// -> parserCore->helperFuncForABC() ....;
}
};
I have seen in the boost testing tools the macro:
BOOST_<level>_EQUAL_COLLECTION(left_begin, left_end, right_begin, right_end)
which can work for streams by using ifstream_iterator.
Does Catch framework provide such a way to compare streams/files?
Not built-in, but then it does not purport to.
For this you write your own matcher.
Here's the documentation's example for integer range checking:
// The matcher class
class IntRange : public Catch::MatcherBase<int> {
int m_begin, m_end;
public:
IntRange( int begin, int end ) : m_begin( begin ), m_end( end ) {}
// Performs the test for this matcher
virtual bool match( int const& i ) const override {
return i >= m_begin && i <= m_end;
}
// Produces a string describing what this matcher does. It should
// include any provided data (the begin/ end in this case) and
// be written as if it were stating a fact (in the output it will be
// preceded by the value under test).
virtual std::string describe() const {
std::ostringstream ss;
ss << "is between " << m_begin << " and " << m_end;
return ss.str();
}
};
// The builder function
inline IntRange IsBetween( int begin, int end ) {
return IntRange( begin, end );
}
// ...
// Usage
TEST_CASE("Integers are within a range")
{
CHECK_THAT( 3, IsBetween( 1, 10 ) );
CHECK_THAT( 100, IsBetween( 1, 10 ) );
}
Clearly you can adapt this to perform any check that you need.
I want to get a pointer from vector's element which has Fd property set on desired value. Right now I am using this ugly code:
User* Game::GetUser(int fd)
{
for(auto& v : users)
if (v.Fd == fd)
return &v;
return nullptr;
}
How can I change this code to be more similar to this:
void Game::RemoveUser(int fd)
{
users.erase(remove_if(begin(users), end(users), [fd](User const& u)
{
return u.Fd == fd;
}), end(users));
}
Or maybe there are other, much better ways to code this?
How can I change this code to be more similar to this
Just use std::find_if with the same predicate:
User* Game::GetUser(int fd)
{
auto it = find_if(begin(users), end(users), [fd](User const& u)
{
return u.Fd == fd;
}));
return it == end(users) ? nullptr : &*it;
}
to avoid code duplication you can use result of find_if for erase as well:
users_type::iterator findUser( int fd)
{
return find_if(begin(users), end(users), [fd](User const& u)
{
return u.Fd == fd;
}));
}
User* Game::GetUser(int fd)
{
auto it = findUser( fd );
return it == end( users ) ? nullptr : &*it;
}
void Game::RemoveUser(int fd)
{
auto it = findUser( fd );
if( it != end(users) )
users.erase( it );
}
you may consider to use different container if such operations has to happen quite often, as both std::find_if and std::remove_if are linear to number of elements. Or you may want to keep users sorted and use std::equal_range() instead of std::find_if() which is log(N), but you would need to use findUser to find proper location to insert or use std::sort after insertion(s).
Consider this unit test:
std::bitset<8> temp( "11010100" );
reverseBitSet( temp );
CPPUNIT_ASSERT( temp == std::bitset<8>( "00101011" ) );
This implementation works:
template<size_t _Count> static inline void reverseBitSet( std::bitset<_Count>& bitset )
{
bool val;
for ( size_t pos = 0; pos < _Count/2; ++pos )
{
val = bitset[pos];
bitset[pos] = bitset[_Count-pos-1];
bitset[_Count-pos-1] = val;
}
}
While this one does not:
template<size_t _Count> static inline void reverseBitSet( std::bitset<_Count>& bitset )
{
for ( size_t pos = 0; pos < _Count/2; ++pos )
{
std::swap( bitset[pos], bitset[_Count-pos-1] );
}
}
Result is "11011011" instead of "00101011"
Why is swap doing it wrong?
This:
std::swap( bitset[pos], bitset[_Count-pos-1] );
should actual fail to compile. operator[] for a std::bitset doesn't return a reference, it returns a proxy object. That proxy object isn't an lvalue, so it cannot bind to the T& in std::swap. I'm assuming the fact that it compiles at all means that you're using MSVC which has an extension that allows binding temporaries to non-const references - at which point you're probably just swapping the proxies and not what the proxies are actually referring to.
Side-note: The name _Count is reserved by the standard, as is any other name which begins with an _ followed by a capital letter.
In my Python code I have an issue that I need clarified before I start translating to c++: how to make proper dictionaries/lists that I can use the equivalent of "if var in _" in.
arbitrary example that needs translation:
CONFIRMATION = ('yes', 'yeah', 'yep', 'yesh', 'sure', 'yeppers', 'yup')
DECLINATION = ('no', 'nope', 'too bad', 'nothing')
varResponse = str(input('yes or no question'))
if varResponse in CONFIRMATION:
doSomething()
elif varResponse in DECLINATION:
doSomethingElse()
else:
doAnotherThing()
It's fairly easy to do similar tasks using arrays, like:
if (userDogName == name[0])
execute something;
but what I need is something like:
if (userDogName is one of a population of dog names in a dictionary)
execute something;
You can use the STL container class set. It uses balanced binary trees:
#include <iostream>
#include <set>
#include <string>
int main(int argc, char* argv[])
{
std::set<std::string> set;
std::set<std::string>::const_iterator iter;
set.insert("yes");
set.insert("yeah");
iter = set.find("yess");
if (iter != set.end( ))
{
std::cout << "Found:" << *iter;
}
else
{
std::cout << "Not found!";
}
return 0;
}
C++11 permits a solutions that's very similar to the Python code:
#include <iostream>
#include <set>
#include <string>
using namespace std;
set<string> CONFIRMATION = {"yes", "yeah", "yep", "yesh", "sure", "yeppers", "yup"};
set<string> DECLINATION = {"no", "nope", "too bad", "nothing"};
int main() {
cout << "yes or no question";
string varResponse;
getline(cin, varResponse);
if (CONFIRMATION.find(varResponse) != CONFIRMATION.end()) {
doSomething();
} else if (DECLINATION.find(varResponse) != DECLINATION.end()) {
doSomethingElse();
} else {
doAnotherThing();
}
}
Well, C++ isn't well suited for small throw-off programs, because it doesn't provide much infra-structure. You're meant to create your own infra-structure (such as, well, even just plain sets!) on top of the standard library. Or use some 3rd-party libraries, i.e. your choice.
So while Python comes with batteries included, with C++ there is no strong pressure to accept the particular provided batteries (because there are none), but you have to at least choose batteries.
For just the basic code, the Python snippet
CONFIRMATIONS = ("yes", "yeah", "yep", "yesh", "sure", "yeppers", "yup")
DECLINATIONS = ("no", "nope", "too bad", "nothing")
response = raw_input( "yes or no? " )
if response in CONFIRMATIONS:
pass # doSomething()
elif response in DECLINATIONS:
pass # doSomethingElse()
else:
pass #doAnotherThing()
can look like this in C++:
typedef Set< wstring > Strings;
Strings const confirmations = temp( Strings() )
<< L"yes" << L"yeah" << L"yep" << L"yesh" << L"sure" << L"yeppers" << L"yup";
Strings const declinations = temp( Strings() )
<< L"no" << L"nope" << L"too bad" << L"nothing";
wstring const response = lineFromUser( L"yes or no? " );
if( isIn( confirmations, response ) )
{
// doSomething()
}
else if( isIn( declinations, response ) )
{
// doSomethingElse()
}
else
{
// doAnotherThing()
}
But then, it relies on some infra-structure having been defined, like the Set class:
template< class TpElem >
class Set
{
public:
typedef TpElem Elem;
private:
set<Elem> elems_;
public:
Set& add( Elem const& e )
{
elems_.insert( e );
return *this;
}
friend Set& operator<<( Set& s, Elem const& e )
{
return s.add( e );
}
bool contains( Elem const& e ) const
{
return (elems_.find( e ) != elems_.end());
}
};
template< class Elem >
bool isIn( Set< Elem > const& s, Elem const& e )
{
return s.contains( e );
}
I used an operator<< because still as of 2012 Visual C++ does not support C++11 curly braces list initialization.
Here set is std::set from the standard library.
And, hm, the temp thingy:
template< class T >
T& temp( T&& o ) { return o; }
And, more infra-structure, the lineFromUser function:
wstring lineFromUser( wstring const& prompt )
{
wcout << prompt;
wstring result;
getline( wcin, result )
|| throwX( "lineFromUser: std::getline failed" );
return result;
}
Which, relies on a throwX function:
bool throwX( string const& s ) { throw runtime_error( s ); }
But that's about all, except that you have to put the C++ code I showed first, into some function, say, call that cppMain, and invoke that from your main function (even more infra-structure to define!):
int main()
{
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
wcerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
So, to do things even half-way properly in C++, there is some steep overhead.
C++ is mainly for larger programs, and Python (which I often use) for smallish programs.
And yes, I know that some students may or will react to that statement, either they feel that it's a slur on C++ to say that it's no good for small programs (hey, I make those all the time!) and/or it's a slur on Python to say that it's no good for large systems (hey, haven't you heard of YouTube, you dumb incompetent person?), but, that's the way that it is. Sometimes it can be more convenient to use the hammer one has to fasten a screw, so sometimes I, for example, use C++ to do some small task. But generally that's because it would be too much hassle to install Python on the machine at hand, and in general, to do a task X, it's best to use tools that have been designed for X-like work.
This can be solved using std::find on any Standard Template Library container.
std::vector<std::string> answers;
std::string input;
...
if(std::find(answers.begin(), answers.end(), input) != answers.end()) {
/* input was found in answers */
} else {
/* input was not found in answers */
}
For larger lists, it may be better to store your lists in a std::set object instead, as Tilo suggested. std::find will work the same.