Can i call a function in initialize list? please see this code:
#include <string>
using namespace std;
class A {
public:
A(string path) : s(cfg.getRoot()) { // before i call getRoot, i need to call cfg.readFile(path.c_str()), is there any methods? (readFile return void)
}
private:
libconfig::Config cfg;
const libconfig::Setting & s; // const &, so initalizer list is the only chance for me to init it
}
You can also make use of the comma operator (although this may or may not be harder to understand for a reader):
A(string path) : s((cfg.readFile(path.c_str()), cfg.getRoot())) {}
The built-in comma operator evalues from left-to-right and discards the result of the left-hand expression. Note that the double parentheses are necessary. Otherwise it will be parsed as two function arguments to s
's constructor.
This will not work correctly if the return type of cfg.readFile(path.c_str())
has an overloaded comma operator (which is however very rare). In that case you need to cast the result to void
in order to discard the return value:
A(string path) : s((static_cast<void>(cfg.readFile(path.c_str())), cfg.getRoot())) {}
The lambda approach was already given. You can avoid repeating the return type if you use decltype(auto)
:
A(string path) : s([this]()->decltype(auto){
cfg.readFile(path.c_str());
return cfg.getRoot();
}()) {}
Again it is a matter of style, whether you prefer giving the return type explicitly or not.
As noted by @songyuanyao in a comment below, if you do not specify a return type or appropriate placeholder, then you will get into trouble if cfg.getRoot
returns a reference, because the default lambda type is an auto
placeholder, which will cause contruction of a temporary object from the reference, which you would then bound to s
and will immediately be destroyed again.