Reputation: 13410
I have written a class to perform output of data stored in unordered_map
according to the pattern. I expect this pattern to be passed to the object at the time of it creation and stay not changed during object lifetime.
This is the class I wrote first:
class Format {
public:
Format(const string output_pattern);
string interpolate(const boost::unordered_map<string, string> & field_values);
private:
...
};
I wanted to use Formatter
in another class this way:
class A {
private:
Format formatter;
public:
A(const std::map<std::string, std::string> & info, ... other parameters) {
std::map<std::string, std::string>::const_iterator it;
it = info.find("format");
if (it == info.end()) {
throw std::runtime_error("Can't find 'format' in info");
} else {
formatter = Format(it->second);
}
}
};
As you see, there is a bit of work before I can call constructor. No surprise, it doesn't work as format
is first initialized with default constructor (which is missing), and second it expects assignment operator defined for formatter = Format(it->second);
line.
I can't initialize formatter
like this:
A(const std::map<std::string, std::string> & info, ... other parameters):
formatter(...) {
...
}
because I have first to extract parameter to pass as formatter
initializer.
So, eventually I solved it this way:
class Format {
public:
Format();
void set_pattern(const string output_pattern);
string interpolate(const boost::unordered_map<string, string> & field_values);
private:
...
};
class A {
private:
Format formatter;
public:
A(const std::map<std::string, std::string> & info, ... other parameters):
formatter()
{
std::map<std::string, std::string>::const_iterator it;
it = info.find("format");
if (it == info.end()) {
throw std::runtime_error("Can't find 'format' in info");
} else {
formatter.set_pattern(it->second);
}
}
};
What I really don't like about this is that this turned immutable formatter
object into mutable. Here it is not a big issue. But I don't need it to be mutable and don't like it when I have to make it mutable just because I can't express it in code when it is immutable.
Is there any another good approach I can take to initialize it in constructor in my case?
Upvotes: 1
Views: 351
Reputation: 8313
You could do a helper private function to do the actual work:
class A {
private:
SomethingA before;
Format formatter;
SomethingB after;
public:
A(const std::map<std::string, std::string>& info) :
formatter(extractFormat(info))
{
// ...
}
private:
string extractFormat(const std::map<std::string, std::string>& info)
{
// Be careful here! The object is not constructed yet, you can't fully use it
// this->before => ok
// this->after => not ok
// you could make this function static just to be safe
}
};
Upvotes: 2