How to pass list to Cmake function by reference - list

I want to pass a list to a function in Cmake, edit the list, and use the new value in the calling function.
I have tried this code:
function(foo my_list)
message(
STATUS
${${my_list}}
)
string(REPLACE "-O4" "-Oz" ${my_list} "${${my_list}}" PARENT_SCOPE)
endfunction(foo)
......
foo(my_list)
message(
STATUS
${${my_list}}
)
I expect that the message from inside the foo function will print the list value, but instead it prints "my_list"
also, I expect that after foo function returns, the my_list will be changed ("-Oz" instead of "-O4", but its not being changed)

Related

Conditionally adding arguments to a constructor (C++)

Is there a way to conditionally add arguments to a constructor? I'd also like to know what this type of construction is called so I can search it myself.
I'm creating a boost::process::child using a constructor where I can pass any properties and things are mostly working great:
m_proc = new boost::process::child(
m_context,
boost::process::exe = m_config.exe,
boost::process::args = m_config.args,
boost::process::env = m_config.Environment,
boost::process::start_dir = m_config.WorkingDirectory,
boost::process::std_out > m_stdout_pipe,
boost::process::std_err > m_stderr_pipe,
boost::process::on_exit = [this](int i, auto e){OnProcExit(i, e);},
boost::process::extend::on_setup = [this](auto&){OnProcSetup();},
boost::process::extend::on_success = [this](auto&){OnProcSuccess();},
boost::process::extend::on_error = [this](auto&, auto ec){OnProcError(ec);}
);
UNTIL I call ls with no arguments. Then it returns
/usr/bin/ls: cannot access '': No such file or directory
Process Exited (code:2)
If m_config.args is empty, I want to avoid passing it. I tried:
m_proc = new boost::process::child(
...
boost::process::exe = m_config.exe,
m_config.args.empty() ? (void) : (boost::process::args = m_config.args),
...
);
but that gives:
error: expected primary-expression before ‘void’
I tried:
m_proc = new boost::process::child(
...
boost::process::exe = m_config.exe,
boost::process::args = m_config.args.empty() ? {} : m_config.args,
...
But that gives:
initializer list cannot be used on the right hand side of operator ?
error: expected primary-expression before ‘{’ token
I understand that for this particular case, I could combine exe and args to make a cmd, but I'd also like to conditionally add other arguments like boost::process::shell or boost::process::stdin.
If I need to call different constructor code for every set of options, I would need to write N! calls to constructors where N is the number of options and that grows fast.
This is ugly.
C++ isn't python, there isn't any named parameters in C++, so this solution makes use of global variables (boost::process::args) which are fundamentally not thread safe and prone to usage errors as you experienced.
In the boost documentation they state you don't need to use the global vars, so you can directly use the your config members here:
m_proc = new boost::process::child(
m_context,
m_config.exe,
m_config.args,
m_config.Environment,
[...]
By the way, the error you're reporting isn't due to a bad empty list passing (you can have m_config.args = {}) but probably to a wrong command argument list creation (if the list is empty, the boost::process::child code should create an non-empty string for the process's argument list, containing the executable name as the first argument).
The error you are reporting:
/usr/bin/ls: cannot access '': No such file or directory
is likely due to the wrong argument list being generated by boost and it's not due to your (empty) args array.
So I would put a debug breakpoint on the Popen syscall here and walk backward until I figure out what went wrong in building the argument string.
Using a global variable like a parameter here is syntax candy, but it means operator overloading to an unspecified object (as stated in the documentation), so you actually don't know what's going on here (a = b when a is unknown can be anything in C++, like a crazy making b set to the value of a as in T& operator =(T & b) { b = *this; return *this; }). You'll need to debug what's going on here to figure out what is happening. As a short advice, try to avoid using undefined object if it's not required and unclear, and stick to usual C++ practices.

perl xs - can't return a new custom c++ object from method call - returns scalar value instead

In my XS file I have:
As my new method:
matrix *
matrix::new( size_t ncols, size_t nrows )
which returns a matrix object like it should and I can invoke methods.
Then I have a method call which creates a new matrix object and is supposed to return it as a new matrix:
matrix *
matrix::getInnerMatrix( )
PREINIT:
char * CLASS = (char *)SvPV_nolen(ST(0));
CODE:
RETVAL = static_cast<matrix*>(THIS->matrix::getInnerMatrix());
OUTPUT:
RETVAL
However the returned type is matrix=SCALAR(0x122f81c) and therefore I am unable to invoke any method calls from this object as the perl interpreter seems to be viewing the returned type as a scalar value type instead of a 'matrix' object. Here is a test script:
$m1 = matrix::new(matrix,4,4);
#arr = ( 1 .. 16 );
$aref = [#arr];
$m1->assign_aref($aref);
my $m2 = $m1->getInnerMatrix();
print ref $m1; # returns "matrix" (like it should)
print "\n\n";
print ref $m2; # returns "matrix=SCALAR(0x122f81c)" (wrong)
Here is my typemap:
TYPEMAP
matrix * O_MATRIX
OUTPUT
O_MATRIX
sv_setref_pv( $arg, CLASS, (void*)$var );
INPUT
O_MATRIX
if ( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) {
$var = ($type)SvIV((SV*)SvRV( $arg ));
}
else {
warn( \"${Package}::$func_name() -- ${var} not a blessed SV reference\" );
XSRETURN_UNDEF;
}
What changes must I make in my XS file, or any other file to ensure that a pure matrix object is returned?
When using XS with C++, the XS preprocessor inserts THIS for instance methods and CLASS for static methods. A method called new is treated as a static method. This allows the resulting xsubs to be used as instance methods/class methods by default: matrix->new and $m->getInnerMatrix().
Your typemap uses the CLASS variable which is not provided for instance methods. In your case, I would hard-code the package name in the type map instead:
OUTPUT
O_MATRIX
sv_setref_pv( $arg, "matrix", (void*)$var );
The typemap is also used when an argument of that type is not used as the invocant. E.g. consider this xsub:
matrix*
some_other_xsub(x)
int x
Here there would not by a CLASS variable for the matrix* return value either.
Note that lowercase package names should only be used for pragma packages (like strict or warnings). Please use CamelCase for your classes.
Your attempt to provide your own value for CLASS failed because SvPV_nolen() stringifies the reference and does not get the reference type. I.e. it's equivalent to "$m", not to ref $m. A more correct alternative would have been to use sv_ref():
char* CLASS = SvPV_nolen(sv_ref(NULL, THIS, true));
The third parameter to sv_ref() makes this function work like the Perl function ref, i.e. return the class name if the scalar is blessed, not just the underlying reference type.

Get a pointer to a subordinate YAML::Node

I am writing a config file library, and I'd like to have a pointer to a sub-node to pass to functions expecting YAML::Node*, for example for building up a YAML document.
I can create a new Node and get a pointer easily enough:
YAML::Node* foo = new YAML::Node(); // Null node
and I can add a new sub node easily enough:
(*foo)["bar"] = baz;
However, I don't know how to get a pointer to (*foo)["bar"]. If I try
&((*foo)["bar"]);
I get error: taking address of temporary, which is true, because the [] operator returns a YAML::Node. Is there a way to get a pointer to (*foo)["bar"] so that I can pass it to something like
void f(YAML::Node* const blah)
{
(*blah)["banana"] = 1;
}
which is useful, because then I can build up a tree with recursive calls to f.
Just pass a YAML::Node, not a pointer. YAML::Node is already a reference type, so you can pass it like a pointer.

Binding a Lua table function to a C++ variable using LUAPlus

I want to link a Lua table function to a C++ variable using LUAPlus. So far using what information I can find on the web, I've managed to call a table function using DoString("tableName:functionName"), but I want to be able to call the function through a variable. I know its possible but I cant figure out what I'm doing wrong.
In the code I've added, pLuaState->DoString("table1:prints()") works fine and prints everything as needed.
When I try to get the function and call it using the func variable, my program crashes with
error message
Assertion failed: 0, file .../luafunciton.h, line 41
If I remove all the prints in the prints() function in Lua except "print("in prints")", everything works fine. Based on this I assume that GetByName("functionName") returns a function that doesn't contain a reference to its parent table. And this is where I get stuck.
main.cpp
pLuaState = LuaPlus::LuaState::Create(true);
pLuaState->DoFile("test.lua");
LuaObject globals = pLuaState->GetGlobals();
LuaObject metaTableObj = pLuaState->GetGlobals().Lookup("RandomMove");
if (metaTableObj.IsNil())
{
metaTableObj = pLuaState->GetGlobals().CreateTable("RandomMove");
}
metaTableObj.SetObject("__index", metaTableObj);
metaTableObj.RegisterObjectDirect("GetX", (TestLua*)0, &TestLua::GetX);
metaTableObj.RegisterObjectDirect("SetX", (TestLua*)0, &TestLua::SetX);
TestLua obj1(6);
LuaObject table1Obj = pLuaState->GetGlobals().CreateTable("table1");
table1Obj.SetLightUserData("__object", &obj1);
table1Obj.SetObject("__index", metaTableObj);
table1Obj.SetMetaTable(metaTableObj);
pLuaState->DoString("table1:prints()");
auto prints = table1Obj.GetByName("prints");
if (!prints.IsFunction())
cout << "nil function" << endl;
else
{
LuaPlus::LuaFunction<void> func(prints);
func();
}
test.lua
print("test.lua")
RandomMove =
{
_thing = 1
}
function RandomMove:SetThing()
print("I am "..tostring(self.__object))
end
function RandomMove:prints()
print("in prints")
print("__object is: " .. tostring(self.__object))
print("_thing is: ".. tostring(self._thing))
print(self:GetX())
end
Any help would be appreciated.
You are correct. Functions do not know anything about their "parents" or their "objects" or anything. That's why the : calling syntax exists. The call table1:prints() is identical to table1.prints(table1) (only lua ensures that table1 is evaluated only once.
So if you grab the function from the table/etc. directly when you call it directly you need to ensure that you pass the correct table/etc. as the first argument (before any other arguments the function expects).

Pass method parameter to an action in googlemock

I use Gmock for a method call, that returns an element of the QList heightsFromCsvResult as out parameter. Here is the currently working code:
EXPECT_CALL(*_mockAttributeRepository, getGeometryHeightValues(_,_))
.WillOnce(DoAll(SetArgReferee<1>(heightsFromCsvResult.at(0)), Return(true)))
.WillOnce(DoAll(SetArgReferee<1>(heightsFromCsvResult.at(1)), Return(true)))
.WillOnce(DoAll(SetArgReferee<1>(heightsFromCsvResult.at(2)), Return(true)))
.WillOnce(DoAll(SetArgReferee<1>(heightsFromCsvResult.at(3)), Return(true)));
The first parameter lineNumber from
getGeometryHeightValues(int lineNumber, QPair<QString, QString>)
is the index for heightsFromCsvResult.at(lineNumber).
Now I try to use Gmock in a more generic way:
int* mockLineNumber = new int;
EXPECT_CALL(*_mockAttributeRepository, getGeometryHeightValues(_,_))
.Times(4)
.WillRepeatedly(DoAll(SaveArg<0>(mockLineNumber), SetArgReferee<1>(heightsFromCsvResult.at(*(mockLineNumber))), Return(true)));
But this code does not work, because mockLineNumber is never written by Gmock. But the EXPECT_CALL is satisfied.
Does anyone see the problem in the code?
Using a variable set with SaveArg within the same EXPECT_CALL does not seem to be working, what you could do instead is to go through a custom action that sets the second argument using argument 0 as index on the passed container.
ACTION_P(SetArg1WithValueFromPassedArgumentUsingArg0AsIndex, param)
{
arg1 = param.at(arg0);
}
int* mockLineNumber = new int;
EXPECT_CALL(*_mockAttributeRepository, getGeometryHeightValues(_,_))
.Times(4)
.WillRepeatedly(DoAll(SaveArg<0>(mockLineNumber), SetArg1WithValueFromPassedArgumentUsingArg0AsIndex(heightsFromCsvResult), Return(true)));
Unless you need mockLineNumber for something else you could remove that part.