How can we call a function with "parameter=value" in C++? - c++

When reading codes, we will find some functions like this.
g_spawn_async(NULL, new_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL);
I think nobody can figure out what is the meaning of every parameter. In order to understand the code, we have to find the declaration of the function.
gboolean g_spawn_async (const gchar *working_directory,
gchar **argv,
gchar **envp,
GSpawnFlags flags,
GSpawnChildSetupFunc child_setup,
gpointer user_data,
GPid *child_pid,
GError **error);
How can we call a function like the following format in C++?
g_spawn_async(working_directory=NULL,
argv=new_argv,
envp=NULL,
flags=G_SPAWN_SEARCH_PATH,
child_setup=NULL,
user_data=NULL,
child_pid=NULL,
error=NULL);
I think this one will be more readable and I can understand the code without looking for the declaration of the function.
I know Python can do this. How can C++ do this?

C++ doesn't support this natively, so you can't do it with just any old existing function. If you're creating your own API though, you can use what's called the Named Parameter Idiom to emulate it. The example from the link:
File f = OpenFile("foo.txt")
.readonly()
.createIfNotExist()
.appendWhenWriting()
.blockSize(1024)
.unbuffered()
.exclusiveAccess();

This is not possible in C or C++.
I understand your pains with this. I personally think that it is a sign of bad design to have a function take over 9000 arguments, especially if most of them are NULL or placeholder values. Many POSIX-standardized functions for example take some kind of struct that accumulates all necessary values into one, easy to understand argument.

No, this can't be done. But you can assign the NULL values to the variables and then pass them as parameters if it helps with your readability!
g_spawn_async(working_directory, argv, envp,flags,child_setup , user_data, child_pid, error);

The BOOST parameter library can help you. It works well and is portable....
See http://www.boost.org/doc/libs/1_54_0/libs/parameter/doc/html/index.html

It's certainly possible. It's not even particularly difficult,
but it does involve a lot of code. Something like the following
could be used:
enum MyFuncParamId
{
myA,
myB,
myC,
myD,
unknown
};
class MyFuncParam
{
union OneParam
{
double aOrB;
C c;
int d;
OneParam() {}
~OneParam() {}
};
OneParam myParam;
MyFuncParamId myId;
public:
MyFuncParam( MyFuncParamId id, double value )
: myId( id )
{
switch ( myId ) {
case myA:
case myB:
myParam.aOrB = value;
break;
case myC:
assert( 0 );
abort();
case myD:
myParam.d = value;
break;
}
}
MyFuncParam( MyFuncParamId id, C const& value )
: myId( id )
{
switch ( myId ) {
case myA:
case myB:
case myD:
assert( 0 );
abort();
case myC:
new (&myParam.c) C( value );
break;
}
}
MyFuncParam( MyFuncParamId id, int value )
: myId( id )
{
switch ( myId ) {
case myA:
case myB:
myParam.aOrB = value;
break;
case myC:
assert( 0 );
abort();
case myD:
myParam.d = value;
break;
}
}
MyFuncParam( MyFuncParam const& other )
: myId( other.myId )
{
switch ( myId ) {
case myA:
case myB:
myParam.aOrB = other.myParam.aOrB;
break;
case myC:
new (&myParam.c) C( other.myParam.c );
break;
case myD:
myParam.d = other.myParam.d;
break;
}
}
~MyFuncParam()
{
switch( myId ) {
case myC:
myParam.c.~C();
break;
}
}
MyFuncParam& operator=( MyFuncParam const& ) = delete;
friend class MyFuncParamGroup;
};
class MyFuncRouter
{
MyFuncParamId myId;
public:
MyFuncRouter( MyFuncParamId id ) : myId( id ) {}
MyFuncParam operator=( double value )
{
return MyFuncParam( myId, value );
}
MyFuncParam operator=( C const& value )
{
return MyFuncParam( myId, value );
}
MyFuncParam operator=( int value )
{
return MyFuncParam( myId, value );
}
};
static MyFuncRouter a( myA );
static MyFuncRouter b( myB );
static MyFuncRouter c( myC );
static MyFuncRouter d( myD );
struct MyFuncParamGroup
{
bool aSet;
bool bSet;
bool cSet;
bool dSet;
double a;
double b;
C c;
int d;
MyFuncParamGroup()
: aSet( false )
, bSet( false )
, cSet( false )
, dSet( false )
{
}
void set( MyFuncParam const& param )
{
switch ( param.myId ) {
case myA:
assert( !aSet );
aSet = true;
a = param.myParam.aOrB;
break;
case myB:
assert( !bSet );
bSet = true;
b = param.myParam.aOrB;
break;
case myC:
assert( !cSet );
cSet = true;
c = param.myParam.c;
break;
case myD:
assert( !dSet );
dSet = true;
d = param.myParam.d;
break;
}
}
};
void
myFunc(
MyFuncParam const& p1,
MyFuncParam const& p2,
MyFuncParam const& p3,
MyFuncParam const& p4)
{
MyFuncParamGroup params;
params.set( p1 );
params.set( p2 );
params.set( p3 );
params.set( p4 );
std::cout << "a = " << params.a
<< ", b = " << params.b
<< ", c = " << params.c
<< ", d = " << params.d
<< std::endl;
}
Notes:
I've used C++11 here. The same thing can be done in earlier
versions of C++, by replacing the type C in the union with
unsigned char c[sizeof( C )];, adding something to the union
to ensure correct alignment (if necessary), and a lot of type
casting.
This would be a lot simpler with boost::variant (instead of
the union) and boost::optional (in MyFuncParamGroup).
I didn't have Boost available, so I did most of what they do
explicitly. (Which of course, makes the code a lot longer.)
I've intentionally used two parameters with the same type,
and a user defined type (C) with non-trivial constructors,
to show how these are handled.
You'd probably want a bit more encapsulation, and a bit more
error checking.
But the real question is: do you really want to go this route?
The amount of code increases linearly with the number of
parameters. And with any decent editor, you can temporarily put
the parameter list from the function declaration to the right of
your screen, and fill out the parameters to the left, directly
along side of the parameter declaration. (In gvim, I'll usually
use block editing mode for this, but :vsplit can also be
used.)

Named parameters are very useful and I was even considering that in a language they should be the only way to call a function except for a single obvious parameter if that is present.
sin(x) // the obvious main parameter
sin(x, unit=DEGREE) // any other must be named
C++ unfortunately doesn't have them.
More importantly C++ lacks the metaprogramming ability needed to be able to implement them.
While there are tricks that can try to somewhat mimic named parameters and even if the resulting code can look almost reasonable, what is totally indecent is the code you need to write to get that simulation and that there is no way in C++ to generate that code.
What I mean is that while it's possible to write a function accepting named parameters emulated reasonably, the code for the function itself is hideous and cannot be automatically generated in C++. This means that no one will write functions that way so the feature is still not present.
My guess is that named parameters are missing because of a mix of ignorance (they existed way before C++ was invented, probably even before C) and of pride (even in C++11 the language metaprogramming abilities are pathetic and things trivial like say enumerating at compile time the members of a structure or the parameters of a function is impossible).

Related

Adding XPointer/XPath searches to ALL(?) C++ JSON libraries, is it doable?

Is it possible to extend all(?) existing C++ JSON libraries with XPath/XPointer or subset with just one C++ implementation? At least those with iterators for object and array values?
I have reviewed three C++ JSON libraries (reviewing nlohmann, Boost.JSON and RapidJSON) to see the internals and check their search functionality. Some have implemented Json pointer. Json pointer is basic, almost like working with json as a name-value list.
XML has XPath and XPointer searches and rules are standardized. With XPath and XPointer you can do more.
One reason to reviewing these libraries was to see if it is possible to extend any of them with better search functionality. Or might it be possible to extend all(?) C++ JSON libraries at once?
A longer text describing this can be found here, trying to be brief.
I tried to do one traverse method that selects json values with one specific property name and that method should work an all tested JSON libraries. If I got that to work it may be possible to add more search logic and get it to work on almost all C++ JSON.
I got this C++ templated function to work an all tested json libraries. It can walk the JSON tree and select json values on all tested libraries.
What is needed to is to implement specializations of is_object, is_array, compare_name, get_value, begin and end. That are just one liners so it's easy.
template<typename json_value>
bool is_object( const json_value* p )
{ static_assert(sizeof(json_value) == 0, "Only specializations of is_object is allowed"); }
template<typename json_value>
bool is_array( const json_value* p )
{ static_assert(sizeof(json_value) == 0, "Only specializations of is_array is allowed"); }
template<typename iterator>
bool compare_name( iterator it, std::string_view stringName )
{ static_assert(sizeof(it) == 0, "Only specializations of compare_name is allowed"); }
template<typename iterator, typename json_value>
const json_value* get_value( iterator it )
{ static_assert(sizeof(it) == 0, "Only specializations of get_value is allowed"); }
template<typename iterator, typename json_value>
iterator begin( const json_value& v ) { return std::begin( v ); }
template<typename iterator, typename json_value>
iterator end( const json_value& v ) { return std::end( v ); }
// ------------------------------------------------
// Selects all json values that match property name
template<typename json_value, typename object_iterator,typename array_iterator = object_iterator>
uint32_t select( const json_value& jsonValue, std::string_view stringQuery, std::vector<const json_value*>* pvectorValue = nullptr )
{ assert( is_object( &jsonValue ) || is_array( &jsonValue ) );
uint32_t uCount = 0;
if( is_object( &jsonValue ) == true ) // found object ?
{
for( auto it = begin<object_iterator,json_value>( jsonValue ); it != end<object_iterator,json_value>( jsonValue ); it++ )
{
if( is_object( get_value<object_iterator,json_value>( it ) ) == true )
{ // found object, scan it
auto value = get_value<object_iterator,json_value>( it );
uCount += select<json_value,object_iterator>( *value, stringQuery, pvectorValue );
}
else if( is_array( get_value<object_iterator,json_value>( it ) ) == true )
{ // found array, scan it
auto parray = get_value<object_iterator,json_value>( it );
uCount += select<json_value,object_iterator,array_iterator>( *parray, stringQuery, pvectorValue );
}
else if( compare_name<object_iterator>( it, stringQuery ) == true )
{ // property name matches, store value if pointer to vector
if( pvectorValue != nullptr ) pvectorValue->push_back( get_value<object_iterator,json_value>( it ) );
uCount++;
}
}
}
else if( is_array( &jsonValue ) == true ) // found array
{
for( auto it = begin<array_iterator,json_value>( jsonValue ); it != end<array_iterator,json_value>( jsonValue ); it++ )
{
if( is_object( get_value<array_iterator,json_value>( it ) ) == true )
{ // found object, scan it
auto value = get_value<array_iterator,json_value>( it );
uCount += select<json_value,object_iterator>( *value, stringQuery, pvectorValue );
}
else if( is_array( get_value<array_iterator,json_value>( it ) ) == true )
{ // found array, scan it
auto parray = get_value<array_iterator,json_value>( it );
uCount += select<json_value,object_iterator,array_iterator>( *parray, stringQuery, pvectorValue );
}
}
}
return uCount;
}
if this works and if I haven't forgot something, shouldn't it be possible to extend all libraries with just one implementation? The additional logic for XPath and XPointer is not dependent on the implementation of these C++ JSON libraries.
Am I missing something

C++ iterator class causes R6025 run-time error in Visual C++

I have the following code, when I run the code below I get 'R6025 run-time error in Visual C++'
CommandParameterAndValue param( "Key", "value" );
parameters.AddParameter( &param );
parameters.HasParameter( "akeyval" );
I am lost, any ideas? Is it something to do with the casting?
typedef std::vector<iCommandParameter *> ParamsVectorList;
class CommandParametersList
{
public:
.... functions here ....
void AddParameter( iCommandParameter *param );
bool HasParameter( std::string parameterKey );
protected:
ParamsVectorList m_parameters;
};
void CommandParametersList::AddParameter( iCommandParameter *param )
{
m_parameters.push_back( param );
}
bool CommandParametersList::HasParameter( std::string parameterKey )
{
ParamsVectorList::iterator it;
CommandParameterAndValue *paramItem = NULL;
bool returnValue = false;
for ( it = m_parameters.begin(); it != m_parameters.end(); it++ )
{
paramItem = static_cast<CommandParameterAndValue *>( *it );
if ( paramItem->GetKey().compare( parameterKey ) == 0 )
{
returnValue = true;
break;
}
}
return returnValue;
}
I need more information to give a complete answer, but if you look here: http://support.microsoft.com/kb/125749
That run-time error means you tried to call a pure virtual function - it couldn't find an implementation. I would suggest running through a debugger and finding which line of code throws this error. Than it should be easy to understand and fix. It's probably happening here:
if ( paramItem->GetKey().compare( parameterKey ) == 0 )

Vector with custom objects: crash when I want to use one received with .at method

I have a class named CConfig, I'm creating new object:
std::vector< CConfig > docs;
CConfig newfile( "somefile.xml", "root" );
printf("%s", newfile.GetTagValue( "servername" )); // this works
docs.push_back( newfile );
When I'm getting this object with .at method
CConfig file = docs.at(0);
printf("%s", file.GetTagValue( "servername" )); // this crashes
Where's the problem?
(im sorry if formatting is wrong but currently I don't use javascript because my bandwidth is ended and max speed is 1kb/s so I'll try to fix it later)
CConfig.h:
class CConfig
{
TiXmlDocument m_doc;
TiXmlElement* m_pRoot;
bool m_bIsLoaded;
public:
CConfig ( void ) {};
CConfig ( const char * pszFileName, const char * pszRootName );
~CConfig ( void ) {};
const char* GetTagValue ( const char * pszTagName );
const char* GetTagAttribute ( const char * pszTagName, const char * pszAttributeName );
TiXmlElement* GetRootElement ( void ) { return m_pRoot; };
bool IsAvailable ( void ) { return m_bIsLoaded; };
};
CConfig.cpp
#include "CConfig.h"
CConfig::CConfig( const char * pszFileName, const char * pszRootName )
{
m_bIsLoaded = m_doc.LoadFile( pszFileName );
if( m_bIsLoaded )
m_pRoot = m_doc.FirstChildElement( pszRootName );
}
const char * CConfig::GetTagValue( const char * pszTagName )
{
if( m_bIsLoaded && m_pRoot )
{
TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
if( element )
return element->GetText();
}
}
const char * CConfig::GetTagAttribute( const char * pszTagName, const char * pszAttributeName )
{
if( m_bIsLoaded && m_pRoot )
{
TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
if( element )
return element->Attribute( pszAttributeName );
}
}
I'm using tinyxml
Your issue is with pointers to old memory. When you add an item to an array, it is copied. Later you leave that scope and the original is destroyed, but ask yourself where the pointer in your copy is pointing? Still to the first (now deleted) object's memory. Uh-oh.
The simplest fix (while avoiding large copy operations) is to make m_doc into a shared pointer (available in the standard in C++11, or via Boost in C++03). That will then handle everything for you rule-of-3 wise. And because the underlying memory won't move, m_pRoot will remain valid until the last copy has been deleted.
If copy-space is not an issue, then fix your Rule of Three violation by properly adding a copy constructor:
CConfig(const CConfig& obj)
: m_doc(obj.m_doc)
, m_bLoaded(obj.m_bLoaded)
, m_pRoot()
{
if (m_bLoaded)
m_pRoot = m_doc.GetRootElement();
}
An assignment operator is also likely in order, but if you don't need it, hide it by declaring it (but not implementing it) as private or use the C++11 delete attribute feature.
Interestingly enough, you don't even need the m_bLoaded member. A non-NULL root pointer can indicate your loaded-state, but that is a separate issue. This at least be enough to get you up and running.

C++ Prepend DateTime to console output

Searched around and couldn't find any info on this besides redirecting to files so hopefully someone can help me out.
I have a console application that launches and hooks another process, by default the new process output displays in the first console application.
What I would like to do is prepend a datetime value to all the output, the problem is that I don't control the output from the child process (3rd party app) so the easy solution of adding a datetime to all printed values is unavailable. Is it possible to prepend a string to all stdout?
Since you confirmed C++ (which implies a solution for
std::cout is what is needed, and not for stdout): the
obvious solution is a filtering streambuf:
class TimeStampStreambuf : public std::streambuf
{
std::streambuf* myDest;
std::ostream* myOwner;
bool myIsAtStartOfLine;
protected:
int overflow( int ch )
{
// To allow truly empty lines, otherwise drop the
// first condition...
if ( ch != '\n' && myIsAtStartOfLine ) {
std::string tmp = now();
// function now() should return the timestamp as a string
myDest->sputn( tmp.data(), tmp.size() );
}
myIsAtStartOfLine = ch == '\n';
ch = myDest->sputc( ch );
return ch;
}
public:
TimeStampStreambuf( std::streambuf* dest )
: myDest( dest )
, myOwner( nullptr )
, myIsAtStartOfLine( false )
{
}
TimeStampStreambuf( std::ostream& owner )
: myDest( dest.rdbuf() )
, myOwner( &owner )
, myIsAtStartOfLine( false )
{
myOwner->rdbuf( this );
}
~TimeStampStreambuf()
{
if ( myOwner != nullptr ) {
myOwner->rdbuf( myDest );
}
}
};
And to install it:
// scoped:
TimeStampStreambuf anyName( std::cout );
// Time stamping will be turned off when variable goes out
// of scope.
// unscoped:
std::streambuf* savedStreambuf = std::cout.rdbuf();
TimeStampStreambuf name( savedStreambuf );
// In this case, you have to restore the original streambuf
// yourself before calling exit.
As far as I know, the articles explaining this (from C++
Reports, Sept. 1998) are not on line.
EDIT:
I've actually found them:
http://gabisoft.free.fr/articles-en.html. I can't believe that
the link still works; it's been years since I had an account
with Free.

Error handling for xml parsing

I'm using tinyxml to parse xml files, and I've found that error handling here lends itself to arrow code. Our error handling is simply reporting a message to a file.
Here is an example:
const TiXmlElement *objectType = dataRoot->FirstChildElement( "game_object" );
if ( objectType ) {
do {
const char *path = objectType->Attribute( "path" );
if ( path ) {
const TiXmlElement *instance = objectType->FirstChildElement( "instance" );
if ( instance ) {
do {
int x, y = 0;
instance->QueryIntAttribute( "x", &x );
instance->QueryIntAttribute( "y", &y );
if ( x >= 0 && y >= 0 ) {
AddGameObject( new GameObject( path, x, y ));
} else {
LogErr( "Tile location negative for GameObject in state file." );
return false;
}
} while ( instance = instance->NextSiblingElement( "instance" ));
} else {
LogErr( "No instances specified for GameObject in state file." );
return false;
}
} else {
LogErr( "No path specified for GameObject in state file." );
return false;
}
} while ( objectType = objectType->NextSiblingElement( "game_object" ));
} else {
LogErr( "No game_object specified in <game_objects>. Thus, not necessary." );
return false;
}
return true;
I'm not huffing and puffing over it, but if anyone can think of a cleaner way to accomplish this it would be appreciated.
P.S. Exceptions not an option.
Edit:
Would something like this be preferable?
if ( !path ) {
// Handle error, return false
}
// Continue
This eliminates the arrow code, but the arrow code kind of puts all of the error logging on one place.
Using return values as error codes just leads to such code, it can't be improved much. A slightly cleaner way would use goto to group all error handling into a single block and to decrease the nesting of blocks.
This does however not solve the actual problem, which is using return values as error codes. In C, there is no alternative, but in C++ exceptions are available and should be used. If they are not an option, you're are stuck with what you have.
You could create a macro for that, which encapsulates the if (!var) { .. return false; } and error reporting.
However, I do not see how this can be improved all that much; its just the way it is. C'est la vie. C'est le code...
I'm not huffing and puffing over it,
but if anyone can think of a cleaner
way to accomplish this it would be
appreciated.
I have replaced the nested ifs with return statements on error (this makes the code "flow down" instead of going "arrow shaped". I have also replaced your do loopps with for loops (so I could understand it better).
Is this what you wanted?
const TiXmlElement *objectType = dataRoot->FirstChildElement( "game_object" );
if ( !objectType ) {
LogErr( "No game_object specified in <game_objects>. Thus, not necessary." );
return false;
}
for(; objectType != 0; objectType = objectType->NextSiblingElement( "game_object" )) {
const char *path = objectType->Attribute( "path" );
if ( !path ) {
LogErr( "No path specified for GameObject in state file." );
return false;
}
const TiXmlElement *instance = objectType->FirstChildElement( "instance" );
if ( !instance ) {
LogErr( "No instances specified for GameObject in state file." );
return false;
}
for(; instance != 0; instance = instance->NextSiblingElement( "instance" )) {
int x, y = 0;
instance->QueryIntAttribute( "x", &x );
instance->QueryIntAttribute( "y", &y );
if ( x >= 0 && y >= 0 ) {
AddGameObject( new GameObject( path, x, y ));
} else {
LogErr( "Tile location negative for GameObject in state file." );
return false;
}
}
}
return true;
I know it is a little late, but I know that QueryIntAttribute returns a value which can be used for error handling in case you want this for your attributes too.
if (instance->QueryIntAttribute("x",&x)!=TIXML_SUCCESS)
cout << "No x value found";