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?
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
}
};
Related
Is there a way to match the address of a given parameter in an EXPECT_CALL?
I have code like the following:
EXPECT_CALL(mock1, GetTheData()).WillOnce(Return(theData));
EXPECT_CALL(mock2, SetTheData(_)); // How to check the parameter is the same object as the one returned by GetTheData
// the following was tried but does not work
EXPECT_CALL(mock2, SetTheData(_)).WillOnce([&theData](auto param){ EXPECT_EQ(&theData, param) })
But because the SetTheData function takes its argument by value, the address is different. So I would need to find a way to get the object, before it was passed to the SetTheData function.
I tried some stuff with matches, but that did not seem to work either.
Is this possible at all? If so, how? And if not, why not?
EDIT:
As requested here is a more complete example to give more context.
struct TheData
{
// some stl containers
std::unordered_map<int, std::array<std::byte, 16>> mapToArrays;
std::unordered_map<int, long long> mapToInts;
}
class IDataFetcher
{
public:
virtual TheData GetTheData() = 0;
}
class IDataReceiver
{
public:
virtual void SetTheData(TheData theData) = 0;
}
class DataFetcherMock : public IDataFetcher
{
public:
MOCK_METHOD(TheData, GetTheData, (), (override));
}
class DataReceiverMock
{
public:
MOCK_METHOD(void, SetTheData, (TheData), (override));
}
class Sut
{
public:
Sut(std::unique_ptr<IDataFetcher> fetcher, std::unique_ptr<IDataReceiver> receiver)
void DoTheThing()
{
mReceiver->SetTheData(mFetcher->GetTheData());
}
private:
std::unique_ptr<IDataFetcher> mFetcher;
std::unique_ptr<IDataReceiver> mReceiver;
}
TEST(TestFoo, TestGroupFoo)
{
auto fetcherMock = std::make_unique<DataFetcherMock>();
auto receiverMock = std::make_unique<DataReceiverMock>();
EXPECT_CALL(*fetcherMock, GetTheData()).WillOnce(Return(theData));
EXPECT_CALL(*receiverMock, SetTheData(_)); // Here I want to check the objects are the same
Sut sut(std::move(fetcherMock), std::move(receiverMock));
sut.DoTheThing();
}
The below class is meant to be a top-layer class which brings all the benefits of nlohman::json but offers additional functions.
#include <nlohmann/json.hpp>
class Other { /* ... */ };
class AbstractData : public nlohmann::json
{
public:
AbstractData (const nlohmann::json& json) : nlohmann::json(json) { }
Other createOther(const char* key) { /* create Other class using key */ }
std::string toString() { /* convert to string */ }
/* etc. */
};
But I ran into issues when using operator[]. By default we have
AbstractData a;
auto& val = a["some_key"]; // val is nlohman::json::value_type&
and thus val loses all the extra functions.
When we provide a class function operator[]
const AbstractData& AbstractData::operator[](const char* key) const
{
return nlohmann::json::operator[](key);
}
then
AbstractData a;
auto& val = a["some_key"]; // val is AbstractData&
works as expected. But in order to achieve this, the copy constructor AbstractData (const nlohmann::json& json) is called (which is very inefficient for large objects). And this defeats the purpose of returning a reference in the first place.
I've seen questions like this one Add a method to existing C++ class in other file but they didn't offer help with my specific problem.
Any advice?
I would drop inheritance and wrap de data completely.
Why? Because the moment you need a second AbstractData, you will have to hold and potentially copy the json value. If you wrap the json data instead of using inheritance, then you can act as a view over json data.
class AbstractData {
// view over json
nlohmann::json const* _json_ptr;
auto json() -> nlohmann::json const& {
return *_json_ptr;
}
public:
AbstractData(nlohmann::json const& json) : nlohmann::json(&json) {}
Other createOther(const char* key) {
/* create Other class using key */
}
std::string toString() {}
auto operator[](const char* key) const -> AbstractData {
return AbstractData{&(json()[key])};
}
};
As you can see you can safely return by value, since your class only holds a pointer to your value and is cheap to copy.
If you also want your class to be the owner, you can store the json as a const shared pointer:
class AbstractData {
using root_t = std::shared_ptr<nlohmann::json const>;
// owner of the json root.
root_t _root;
// view over json
nlohmann::json const* _json_ptr;
auto json() -> nlohmann::json const& {
return *_json_ptr;
}
AbstractData(nlohmann::json const& json, root_t root) :
_root(root), _json_ptr(&json) {}
public:
struct new_root_t {} static constexpr new_root{};
AbstractData(new_root_t, nlohmann::json json) :
_root{std::make_shared<nlohmann::json const>(std::move(json))}, _json_ptr{_root.get()} {}
auto operator[](const char* key) const -> AbstractData {
// always pass down the root, so someone will own it
return AbstractData{json()[key], _root};
}
};
Live example
As a side note, you had undefined behaviour:
// return by reference?
const AbstractData& AbstractData::operator[](const char* key) const {
// construct a new, local value
// the local value is destroyed then returned
return nlohmann::json::operator[](key);
}
I strongly suggest to return by value here.
How to store temporary state, needed for the initializer list, in the constructor (on the stack)?
For example, implementing this constructor …
// configabstraction.h
#include <istream>
class ConfigAbstraction
{
public:
ConfigAbstraction(std::istream& input);
private:
int m_x;
int m_y;
int m_z;
};
… using a stateful helper class like this?
// mysillyparserdontworry.h
#include <json/reader.h> //jsoncpp
class MySillyParserDontWorry
{
public:
MySillyParserDontWorry(std::istream& input) { input >> m_parseTree; }
int intByName(const char* name) const { return m_parseTree[name].asInt(); }
private:
Json::Value m_parseTree;
};
My attempt:
// configabstraction.cpp
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: local_parserState(input) // init local variable first: Not possible!
, m_a(local_parserState.intByName("a"))
, m_b(local_parserState.intByName("b"))
, m_c(local_parserState.intByName("c"))
{
MySillyParserDontWorry local_parserState; // ...because it is local
}
With C++11 you could solve this with delegating constructors:
class ConfigAbstraction
{
public:
ConfigAbstraction(std::istream& input);
private:
ConfigAbstraction(const MySillyParserDontWorry& parser);
int m_a;
int m_b;
int m_c;
};
ConfigAbstraction::ConfigAbstraction(const MySillyParserDontWorry& parser)
: m_a{parser.intByName("a")}
, m_b{parser.intByName("b")}
, m_c{parser.intByName("c")}
{
}
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: ConfigAbstraction{MySillyParserDontWorry{input}}
{
}
An alternative solution to your problem would be packing the three individual ints into a common data structure. This would allow you to initialise an object of that type with a private static helper function. Being able to initialise the object instead of assigning to it later also allows for it to be const (if that is required).
Here is an example with std::tuple. But you could also create your own helper struct or even std::array<int, 3>; the basic idea remains the same: have one member object instead of three.
#include <istream>
#include <tuple>
class MySillyParserDontWorry
{
public:
MySillyParserDontWorry(std::istream& input) { /* ... */ }
int intByName(const char* name) const { return /* ... */ 0; }
};
class ConfigAbstraction
{
public:
ConfigAbstraction(std::istream& input);
private:
static std::tuple<int, int, int> parse(std::istream& input)
{
std::tuple<int, int, int> result;
MySillyParserDontWorry parser(input);
std::get<0>(result) = parser.intByName("a");
std::get<1>(result) = parser.intByName("b");
std::get<2>(result) = parser.intByName("c");
return result;
}
std::tuple<int, int, int> const m;
};
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: m(parse(input))
{
}
Why not simply doing the assignments in the constructor's body then?
ConfigAbstraction::ConfigAbstraction(std::istream& input)
: m_a(0)
, m_b(0)
, m_c(0)
{
MySillyParserDontWorry local_parserState;
m_a = local_parserState.intByName("a");
m_b = local_parserState.intByName("b");
m_c = local_parserState.intByName("c");
}
Is there any specific requirement that hinders you doing that?
What an artificial limitation of C++!
It's not an artificial limitation. How should initialisation of local variables be done outside of their function's scope? It would just lead to a great confusion, where variables are actually initialised (naming conflicts aside).
You can not initialize local variables bedfore members. The reason for this is very simple (so that it is NOT an artificial limitation):
Members have to be initialized (constructed) before constructor body begins, because constructor body might access them - and they need to be initialized for this access. On the other hand, local variables do not exist before code enters constructor body (as for any other function).
Conclusion - initialization of local variables before members is impossible.
const fields in C++ must be initialized in the initialization list, this makes non trivial the computation of interdependent values from the constructor parameters.
What is(are) the best way(s) to translate, for example, this piece of java code into c++ ?
public class SomeObject {
private final String some_string;
private final int some_int;
public SomeObject(final String input_filename){
SomeReader reader(input_filename);
some_string = reader.getString();
some_int = reader.getInt();
reader.close();
}
}
I thought of encapsulating a sub-object in SomeObject, but this is just shifting the problem; or constructing the object using a static method:
class SomeObject {
private:
const std::string some_string;
const int some_int;
public:
static SomeObject unserialize(const char * input_filename){
SomeReader reader = new SomeReader(input_filename);
string str = reader.get_string();
int i = reader.get_int();
reader.close();
SomeObject obj(str, i);
return obj;
};
SomeObject(const std::string str, const int i) :
some_string(str),
some_int(i)
{};
}
Is there a better solution ?
Thank you.
This is a great application for C++11 constructor delegation:
class SomeObject {
private:
const std::string some_string;
const int some_int;
public:
// The "real" constructor for SomeObject
SomeObject(std::string str, const int i) :
some_string{std::move(str)},
some_int{i}
{}
// Deserialize from SomeReader (delegates to the primary constructor)
SomeObject(SomeReader& reader) :
SomeObject{reader.get_string(), reader.get_int()} {}
// Deserialize from SomeReader (accepts rvalues,
// delegates to the lvalue constructor)
SomeObject(SomeReader&& reader) :
SomeObject{reader} {}
// Deserialize from named file (delegates to the SomeReader&& constructor)
SomeObject(const char* input_filename) :
SomeObject{SomeReader{input_filename}} {}
};
You can use a delegating ctor and a lambda-function, like this:
SomeObject(const char* filename) : SomeObject([&]{
/* Do calculations here */
return std::make_tuple(...);
}()) {}
SomeObject(std::tuple<...>&& x) : /* ... */ {}
Still, a much better idea is probably a re-design to make use of all the things you can do in C++ and cannot do in Java.
I think you have the right approach.
I would recommend couple of minor changes.
This is not correct C++.
SomeReader reader = new SomeReader(input_filename);
Perhaps you meant:
SomeReader reader(input_filename);
You can change the lines:
SomeObject obj(str, i);
return obj;
to
return SomeObject(str, i);
I have an object, every member variable in this object has a name which I can acquire it by calling get_name() ,what I want to do is concatenate all the names of the member variables in alphabetical order, then do something. for example:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
}
//skip the get_name(), set_name() and others
private:
string m_local_name;
T m_type_var;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
...
}
I have to hard-code like this:
object o;
string sign = o.m_base.get_name();
sign += o.m_team.get_name();
I need a function to do this instead of copying and pasting when the object varies. Anyone has an idea?
One way to do this in normal C++, provided all of the members belong to the same class or are derived from some base class will be to use variable number of arguments to a function. An example follows.
#include <stdarg.h>
string concatenateNames(int numMembers, ...)
{
string output;
va_list args;
va_start(args, numMembers);
for(int i = 0; i < numMembers; i++)
{
MemberClass *pMember = va_arg(args, MemberClass*);
output += pMember->get_name();
}
va_end(args);
return output;
}
class Object
{
public:
MemberClass x;
MemberClass y;
MemberClass z;
};
int main()
{
Object o;
string sign = concatenateNames(3, &o.x, &o.y, &o.z);
}
If the types of all the members are different, you can look into variadic templates of C++11x: http://en.wikipedia.org/wiki/Variadic_Templates, but I can't seem to find a way to do otherwise.
If variables which have name have a same type (or these types belongs one hierarchy) you can use map of these vars. Is not good way, but maybe it helps you
Example
class object
{
public:
object() //: m_team("team"), m_base("base")
{
this->vars["m_team"] = CXMLWrapper<string>("team");
//.....
}
public:
map<string, CXMLWrapper<string> > vars;
/*CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;*/
...
}
object o;
string sign;
for(auto& x : o.vars)//i cannot remember syntax of for of map
sign += x.get_name;
PS Sorry for my writing mistakes. English in not my native language.
One method is to have an external library of member names which the CXMLWrapper class updates:-
class BaseXMLWrapper
{
public:
void ListMembers (const char *parent)
{
// find "parent" in m_types
// if found, output members of vector
// else output "type not found"
}
protected:
void RegisterInstance (const char *parent, const char *member)
{
// find 'parent' in m_types
// if not found, create a new vector and add it to m_types
// find 'member' in parent vector
// if not found, add it
}
private:
static std::map <const std::string, std::vector <const std::string> >
m_types;
};
class CXMLWrapper <class T, const char *parent> : BaseXMLWrapper
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
RegisterInstance (parent, p_name);
}
// you could override assignments, copy and move constructors to not call RegisterInstance
//skip the get_name() set_name()
private:
m_local_name;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string, "object"> m_team;
CXMLWrapper<string, "object"> m_base;
...
};
This does add overhead to the construction of objects, but as it's only a constructor overhead it might not affect overall system performance much.
This looks like a "observe pattern", you just need to keep a single copy in object as a member variable "string name_;", and pass the name_s's reference into CXMLWrapper like this:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const string &name)
: local_name_(name)
{
}
//skip the get_name() set_name()
private:
const string &local_name_;
}
class object
{
public:
object()
: team_("team"),
base_("base"),
m_team(team_)
, m_base(base_)
{
}
public:
string team_;
string base_;
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
}