Conditionally adding arguments to a constructor (C++) - 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.

Related

C++ proto2 "expression is not assignable" error

I am trying to figure out how to assign a message field in protobuf2 in C++. Here is a small snippet of the code.
message Sub {
optional double x = 1 [[default = 46.0];
}
message Master {
optional Sub sub_message;
}
Now when I try to initialize a Master message, I got the following error:
Master msg;
msg.mutable_sub_message() = new Sub();
error: expression is not assignable
However, the following code works, and the sub_message is set to default values:
Master msg;
msg.set_sub_message(new Sub());
Can anyone kindly explain why mutable_sub_message() can not be used for assignment?
msg.mutable_sub_message() returns a pointer to the field, i.e. a Sub*. The idea is that you use that pointer to manipulate the field as you need.
Assigning a different pointer to it wouldn't change the value inside the class, it would at most change the temporary pointer that was returned, which doesn't make sense. I guess it could be made to work if mutable_sub_message returned something like a Sub*& (not even sure that syntax is right), but that's not how the library was written.
In a more practical note, calling mutable_sub_message will initialize the subfield, you don't need to do that explicitly. That means you'd usually set a nested field using
Master msg;
msg.mutable_sub_message()->set_x(4.0);
Also, it's always safe to call getters even if a field isn't set, in that case they will always return a default instance. In other words:
double use_field(const Master& msg) {
// This is always safe, and will return the default even if
// sub_message isn't set.
return msg.sub_message().x();
}

Map of Boolean Functions with A Single Argument

I don't have a lot of experience writing C++ and I'm struggling with an issue. The code below is kind of scraped together from snippets. I am writing a class and I want it to have an attribute map of string keys and function values:
std::map< std::string, std::function<bool(std::string)> > selection_filters;
I then want to add pairs as follows:
auto some_func = [] (std::string value) { return value == "some_val"; };
selection_filters["some_key"] = some_func;
//or
selection_filters.insert(std::make_pair("some_key", some_func));
Such that I can:
if ( selection_filters["some_key"]("function param") == true ) {
//etc..
}
This compiles, but throws an error at runtime:
terminating with uncaught exception of type std::__1::bad_function_call: std::exception
I suspect it may have something to do with a discrepancy between std::function<bool(std::string)> in the map definition, and the use of the lambda function [] (std::string value) { ... };
I would very much like to preserve the use of lambda functions and the possibility to access the functions through the subscript operators on the map (map['some_key'](..)) but my knowledge of C++ is not good enough to come up with a solution.
Can someone please point out the error I'm making (and why it is thrown; I want to learn) and provide suggestions for improvement?
See What causes std::bad_function_call?
Missing or empty function. Be sure to check that "some_key" exists in the map before you call the function,
if(selection_filters.find("some_key") != selection_filters.end())
or at least check that the function has a valid target:
if(selection_filters["some_key"])
When you use the [] operator on an std::map, it will insert a default constructed object (or zero) if it is not already in the map. This can (and will) cause lots of invalid entries for keys that you have not explicitly set.

Was it possible to get a pointer to member from an instance of an object?

I was porting some legacy code to VS 2015 when this compiler error halted the build:
error C3867: 'OptDlg::GetFullModel': non-standard syntax; use '&' to create a pointer to member
Going to the corresponding file and line, I saw this:
Manager mgr = GetDocument()->GetManager();
OptDlg dlg;
...
mgr->SetFullModel(dlg.GetFullModel);
if ( dlg.GetFullModel )
mgr->SetSymm(...
GetFullModeland SetFullModel are the getter/setter pair for a member variable in two different classes:
class Manager {
...
bool GetFullModel() { return m_bFullModel; }
void SetFullModel(bool bFlag) { m_bFullModel = bFlag; }
....
};
class OptDlg {
...
void GetFullModel() { return m_bFullModel; }
void SetFullModel(bool bValue) { m_bFullModel = bValue; if ( bValue ) m_bInside = 0;}
Yep, something's wrong. Was dlg.GetFullModel supposed to be a pointer to a member function? I thought those use the class name, not an instance. Not to mention what that would mean for execution semantics...
C++ is still relatively new to me, so I tried Google. It had a lot on function pointers, but they all looked different from what I had:
&OptDlg::GetFullModel // Standard-compliant
vs
OptDlg::GetFullModel // The "normal" way to mess up getting a pointer to member, it seems
vs
dlg.GetFullModel // ?
Is dlg.GetFullModel just another way of getting a pointer to member function? If not, what is the "standard C++ version", if there is one? Is this just another one of those VS 6 "extensions"?
&OptDlg::GetFullModel // Standard-compliant
If your parameter types were supposed to be taking member functions, that's what you'd use. But they take booleans. It looks like you're just missing parentheses on your function calls, and it should be:
mgr->SetFullModel(dlg.GetFullModel());
if (dlg.GetFullModel())
mgr->SetSymm(...
Probably someone was ignoring warnings (or didn't have them on) and hence a pointer value (being produced through whatever shady means) was always being interpreted as non-NULL, hence boolean true.
Is this just another one of those VS 6 "extensions"?
It would appear to be the case, although this comment is the only documented evidence I can find it was an intentional/advertised "feature". Don't see any formal announcement of it being added or taken out.
It strongly looks to me like someone mis-typed dlg.GetFullModel() (which would call the function), not that they were trying to get a member function pointer.
Presumably the legacy compiler let it slide, taking the address of the function without using & and converting the non-null function pointer to bool (with value true) to pass into the set function.

llvm basic block predecessors llvm pred_iterator out of range

I'm trying to iterator over the predecessors of a basic block and I'm getting using the following code:
for (::llvm::PredIterator PI = pred_begin(post_block); PI != pred_end(post_block); PI++)
{
::llvm::BasicBlock *pred = *PI;
if (pred != exec_block)
{ ...
In the line with the if statement, I'm getting the following error:
In instantiation of ‘llvm::PredIterator<Ptr, USE_iterator>::reference llvm::PredIterator<Ptr, USE_iterator>::operator*() const [with Ptr = llvm::BasicBlock; USE_iterator = llvm::Value::use_iterator_impl<llvm::Use>; llvm::PredIterator<Ptr, USE_iterator>::reference = llvm::BasicBlock*]’:LLVMTC.cpp:1489:31:
required from here /usr/local/include/llvm/Support/CFG.h:56:5: error: ‘const class llvm::Value::use_iterator_impl<llvm::Use>’ has no member named ‘atEnd’
assert(!It.atEnd() && "pred_iterator out of range!");
Does anyone have any ideas what might be causing this problem? I'm basing my code off of: http://llvm.org/docs/ProgrammersManual.html#iterating-over-predecessors-successors-of-blocks.
Thanks!
First it's important to address the difference between your approach and the one in the example you're referencing.
In the example, they're define an instance of the pred_iterator type, rather than the PredIterator class you've used, which is defined as
typedef PredIterator<BasicBlock, Value::user_iterator> pred_iterator
and then using the calling pred_begin which returns an instance of pred_iterator(BB) where BB is the basic block you pass.
In your case, you're creating an instance of the PredIterator class and assigning it to the BB pointer, then attempting to dereference upon which it hits this assert:
inline reference operator*() const {
assert(!It.atEnd() && "pred_iterator out of range!");
return cast<TerminatorInst>(*It)->getParent();
}
As an initial solution it might be helpful to try and completely mimic the method used by the example, and then if you still need to use your method, try and diagnose the problem by observing how the typing for PredIterator is defined.
I've been looking though the svn history, Since LLVM 3.5, CFG.h has been moved from include/llvm/Support to include/llvm/IR. So you may want to use the following
#include "llvm/IR/CFG.h"
instead of
#include "llvm/Support/CFG.h"

c++ attempting to reference deleted function

I have been playing around with std::unique_ptr and the std::for_each algorithm to learn them and I then received this error "attempting to reference a deleted function" when I am attempting to move some variables from one container (std::map) to another.
This code is currently executed in a member function. Foo is just a generic class.
std::for_each(m_list1.begin(), m_list1.end(),
[&](std::pair<std::size_t,std::unique_ptr<Foo>> data_pair)
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
});
m_list1.clear();
I tried various things but the problems still persists. I then tried using range-based for instead and suddenly it works.
for (auto& data_pair : m_list1)
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
}
m_list1.clear();
What I want to know is why the second code executed with no problem, while the first code produced the error.
If you need more specific information, Just ask. If there's bad practice in my coding style, please advice on how to make it better.
There are two errors in your for_each code. First, map::value_type is pair<const Key, Value>. Second, your lambda expression is taking the argument by value, which means it attempts to copy the unique_ptr, hence the error. To fix it, take the argument by reference.
[&](std::pair<const std::size_t, std::unique_ptr<Foo>>& data_pair)
// ^^^^^ ^^^
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
}
A better option is to not mention those types explicitly, instead use decltype
[&](decltype(m_list1)::value_type& data_pair)
{
m_list2[data_pair.first] = std::unique_ptr<Foo>(std::move(data_pair.second));
}
Now, your range-based for worked because you were binding the elements of the map to a reference by using for(auto& data_pair : m_list1). You'd have run into the same error as before if you'd instead used for(auto data_pair : m_list1) because that'd have attempted to make a copy of the elements.