C++ constructor with optional parameters - c++

Hi I am new to C++ and I am trying to create a class hierarchy where each class represents a node in a schema document, think json-schema. Have a look at the representation of e.g. a string. A string can have three optional constraints
min_length
max_length
pattern
Furthermore a string is a type so it would make sense to have a base class representing a type from which all types (boolean, number, ...) inherit. Now, one way to achieve this is by writing something like
struct Type {
const std::string m_name;
Type(const std::string& name)
: m_name{name}
{}
virtual X Serialize() const {
//...
}
};
struct String : Type {
const int m_max_len;
const int m_min_len;
const std::string m_pattern;
String(int min_len, int max_len, const std::string& pattern)
: Type("string")
, m_min_len(min_len)
, m_max_len(max_len)
, m_pattern(pattern)
{}
X Serialize() const override {
// If min_length was not set then it should be omitted from the serialized output.
}
};
This String implementation would not make the constraints optional. What to do?
Options:
One could employ a strategy where the default constructor parameters where set to some "illegal" value like INT_MIN (which would work in this case because the length can not be negative) but that would not work in the general case. It could very well be that all possible integers a legal values, the same goes for the pattern parameter.
You do not want to have different constructors for every possible permutation of optional parameters. In this case there are three optional values which would yield 2^3 different constructors. Also it would not be possible for the compiler to distinguish between the constructors String(int min_length) and String(int max_length).
It would be possible to do something like
String(int* min_length = nullptr, int* max_length = nullptr, const std::string* nullptr)
but then you would have to use new/delete or give lvalues for the set parameters.
Finally each member could be a std::unique_ptr.
String(std::unique_ptr<int> min_value nullptr, std::unique_ptr<int> max_value = nullptr, std::unique_ptr<const std::string> pattern = nullptr)
but then you would end up with quite complicated calls when creating an instance of String. Also if implementing a container of Types which may have optional parameters of its own things quickly get out of hand.
Finally, the code must be compatible with C++14.

You can simply use std::optional:
String(const std::optional<int> &min_len, const std::optional<int> &max_len,
const std::optional<std::string> &pattern);
Type *type = new String(5, {}, std::nullptr); // last 2 parameters are omitted.
For C++14 you can use similar constructs that exist in other open source libraries, (e.g. boost::optional, folly::Optional).

I lack reputation points to comment on #Kostas
To be compatible with C++14 you can try experimental namespace which has optional (if it is available/works on your compiler)
#include <experimental/optional>
then you can use
String(std::experimental::optional<int> &min_len,.....)
min_len.value_or(-1)

You can write your own class that can contain value or not if you can't use std::optional. It is not like lot of code. Can make its interface like std::optioal has or can make something different, what matters is data:
class OptInt {
bool set_;
int value_;
public:
OptInt() : set_(false) , value_(0) {}
OptInt(int v) : set_(true), value_(v) {}
// can add other ways how to create it
bool isSet() const {return set_;}
int get() const {if (!set_) throw 666; return value_;}
// can add other operations you want to it.
};
Then you can use such default-constructed OptInt as your default argument and so it will be not set, but if caller provides int argument then it will be set.

Have you tried to use an std::optional (since C++17)?
I know you mentioned the need to use C++14 compatible code, but there is a boost::optional available.

Related

C++ how to initialize/copy const array member from array parameter in constructor

The following class is meant to store a single bool and an array of 100 integers. I want a constructor that takes as parameters a single bool and a 100-element array (which are then copied into the object). The obvious way to write this is the following
class Info {
private:
const int contents[100];
const bool symmetric;
public:
Info (const int contents[100], bool symmetric) : contents(contents), symmetric(symmetric) {}
// ...
};
But unfortunately this does not compile, the contents argument in the member initialiser list (the third contentson that line) seems to be regarded as a pointer.
Can I get this to work or is this a C++ limitation?
I do not want to use std::array or std::vector for space and efficiency reasons. [edited] Mine is a C++ syntax question and not about whether std::array is efficient or not. The answer may be useful in related situations that do not allow the use of std::array. [end edited]
Initializing in the constructor body does not work, because contents is const.
I am using C++14 with clang (CLion in linux) and come from the Java world.
There is also another way other than std::array, but you should use templates and use variadic parameter feature.
Lets assume that the number of elements is amount then first declare your class like :
#include <utility>
template<size_t amount, typename = std::make_index_sequence<amount> >
class Info;
then define your class as the following:
template<size_t amount, size_t ... _Idx>
class Info<amount, std::integer_sequence<size_t, _Idx...> > {
private:
const int contents[amount];
const bool symmetric;
public:
Info (const int contents_[amount], bool symmetric_) : contents{contents_[_Idx]...}, symmetric(symmetric_) {}
};
now you use your class for any amount without any problem:
const int preinfo[3] = {1,2,3};
Info<3> minfo(preinfo, true);
This method will make it very fast but please note that nothing is free and using this code will make your code to produce a bigger binary after compilation!

explicit constructor of the wrong type called

In the following sample, my output is "single param ctor", twice.
My question is twofold, first, why is the bool ctor called rather than the version containing string, and second, is there a way to get the string version called without casting the call?
As an aside, my actual code doesn't call the constructors with hard-coded strings but with something like:
static constexpr auto NONE = "NONE";
Foo aFoo(NONE);
...
#include <iostream>
#include <string>
using namespace std;
struct Foo {
explicit Foo(bool _isVisible = false): id(""), isVisible(_isVisible) {cout << "single param ctor" << endl;}
explicit Foo(const string _id, bool _isVisible = false): id(_id), isVisible(_isVisible) {cout << "multip param ctor" << endl;}
const string id;
bool isVisible;
};
int main(int argc, const char * argv[]) {
shared_ptr<Foo> sharedFoo = make_shared<Foo>("hello");
Foo regFoo("hi");
return 0;
}
This is a limitation of C++ inherited from older C++ and ultimately from C.
Your string literals convert to bool better than to the "user-defined" type std::string.
Instead of casting in the call, you could add a constructor that takes const char*, possibly having it delegate to your existing constructor that takes std::string:
explicit Foo(const char* _id, bool _isVisible = false)
: Foo(std::string(_id), _isVisible)
{};
This constructor will be an "exact match" (or close enough anyway) and prevent bool from stealing the limelight.
Or, since C++14, instead of the cast use the std::string literal, e.g. "hi"s, though you have to remember to do this at the callsite which is a bit "meh" for a general solution.
By the way, if you really want to take your std::string _id parameter by value, don't make it const; you're preventing it from being moved from and necessitating a copy in the member initialiser. Depending on what is going on at your typical callsite, the following may make more sense:
explicit Foo(
string _id,
bool _isVisible = false
)
: id(std::move(_id))
, isVisible(_isVisible)
{}
If you usually pass in an lvalue, though, at least accept a const std::string& to prevent one copy.
why is the bool ctor called rather than the version containing string
Because "hi" is a pointer to char an array of chars that is converted to a pointer to char (thanks, Lightness Races in Orbit), so a number, that i converted to a bool.
there a way to get the string version called without casting the call?
Not really elegant, but... you can pass a second boolean param
Foo regFoo("hi", false);
to exclude the first constructor

find_if on vector<Message*> with bind2nd and functor

I have a vector like this :
typedef vector<Message*> OmciMessages;
OmciMessages omciResponses;
And I have a functor like following which I suspect is not correct :
class isMatching{
public:
bool operator()(const Message* responseMsg,unsigned short transactionid){
return responseMsg->getTransactionId()==transactionid;
}
};
then I call find_if and want to use the functor to find something in the vector but only for a specific transactionid that is inside my class :
OmciMessages::iterator responseit
= find_if(omciResponses.begin(),
omciResponses.end(),
bind2nd(isMatching(),transactionid));
The compiler does not like it and spawns quite a lot of error messages that are hard to interpret typically for template classes.
/repo/stuyckp/ngpon2WW/tools/cm4/tools/GNU/src/gcc/i686-pc-linux-gnu/bin/../lib/gcc/i686-pc-linux-gnu/3.4.6/../../../../../include/c++/3.4.6/bits/stl_function.h:429: error: no type named `first_argument_type' in `class isMatching'
It worked if I did it like this without a function object :
static bool isMatching(Message* responseMsg){
return responseMsg->getTransactionId()==transactionid;
}
transactionid = 5; //global variable being used. yuck, don't like it
find_if(omciResponses.begin(),
omciResponses.end(),
isMatching);
but then I needed a global variable transaction id that was set beforehand which I think is not that good a design.
So how is this supposed to be done with the bind2nd approach ?
Given the version of your compiler, I assume that C++11 is not an option (otherwise the answer is simple: use a lambda).
The old function object binders (deprecated in C++11, removed in C++17) require a bunch of nested typedefs. You need to define result_type, first_argument_type, and second_argument_type as members of isMatching, either directly or via the binary_function helper (which is also deprecated in C++11 and removed in C++17), to use it with bind2nd.
You can also use a plain function taking two arguments, adapt it with ptr_fun (again, deprecated in C++11 and removed in C++17), and then bind with bind2nd.
Or just use a stateful functor, as shown in Piotr's answer.
bind2nd needs your functor class to be adaptable, i.e. provide certain typedefs, including first_argument_type, second_argument_type, and result_type. You can define them by yourself in the functor classes, or inherit from std::binary_function to make it easy:
class isMatching : public std::binary_function<const Message*, unsigned short, bool> {
public:
bool operator()(const Message* responseMsg, unsigned short transactionid) const {
return responseMsg->getTransactionId() == transactionid;
}
};
struct isMatching
{
unsigned short transactionid;
explicit isMatching(unsigned short transactionid) : transactionid(transactionid) {}
bool operator()(const Message* responseMsg) const
{
return responseMsg->getTransactionId() == transactionid;
}
};
std::find_if(omciResponses.begin()
, omciResponses.end()
, isMatching(0));
// ^ transactionId to be searched for
DEMO
Note that if you urge to use std::bind2nd, or the function object would be stateless, then you don't need a function object as a separate class at all:
bool isMatching(const Message* responseMsg, unsigned short transactionid)
{
return responseMsg->getTransactionId() == transactionid;
}
std::find_if(omciResponses.begin()
, omciResponses.end()
, std::bind2nd(std::ptr_fun(&isMatching), 0));
// ~~~~~~~~~~~^ ^ transactionId to be searched for
// transform to a function object
DEMO 2

overloading operator .

Ok, I know that operator. is not overloadable but I need something like that.
I have a class MyClass that indirectly embeds (has a) a std::string and need to behave exactly like a std::string but unfortunately cannot extend std::string.
Any idea how to achieve that ?
Edit: I want that the lines below to compile fine
MyClass strHello1("Hello word");
std::string strValue = strHello1;
const char* charValue = strHello1.c_str();
As per your later edit, that:
MyClass strHello1("Hello word");
std::string strValue = strHello1;
const charValue = strHello1.c_str();
should compile fine, the only solution is to write a wrapper over std::string:
class MyClass
{
private:
std::string _str;
public:
MyClass(const char*);
//... all other constructors of string
operator std::string& ();
//... all other operators of string
const char* c_str();
//... all other methods of string
friend std::string& operator + ( std::string str, Foo f);
};
//+ operator, you can add 2 strings
std::string& operator + ( std::string str, Foo f);
This however is tedious work and must be tested thoroughly. Best of luck!
You can overload the conversion operator to implicitly convert it to a std::string:
class MyClass
{
std::string m_string;
public:
operator std::string& ()
{
return m_string;
}
};
If you're not interested in polymorphic deletion of a string*, you can derived from std::string, just getting the behavior of your class behaving "as-a" std::string. No more, no less.
The "you cannot derived from classes that don't have a virtual destructor" litany (if that's the reason you say you cannot extend it) it like the "dont use goto", "dont'use do-while" "don't multiple return" "don't use this or that feature".
All good recommendation from and for people that don't know what they are doing.
std::string doesn't have a virtual destructor so don't assign new yourcalss to a std::string*. That's it.
Just make your class not having a virtual destructor itself and leave in peace.
Embedding a string and rewriting all its interface just to avoid inheritance is simply stupid.
Like it is stupid writing dozens of nested if to avoid a multiple return, just as its stupid introduce dozens of state flags to avoid a goto or a break.
There are cases where the commonly considered weird things must be used. That's why those things exist.
You can extend an interface without publically deriving from it. This prevents the case of problematic polymorphic destruction (aka no virtual destructor):
#include <iostream>
#include <string>
using namespace std;
class MyClass
: private std::string
{
public:
MyClass(const char* in)
: std::string(in)
{}
// expose any parts of the interface you need
// as publically accessible
using std::string::c_str;
using std::string::operator+=;
};
int main()
{
MyClass c("Hello World");
cout << c.c_str() << "\n";
c += "!";
cout << c.c_str() << "\n";
// Using private inheritance prevents casting, so
// it's not possible (easily, that is) to get a
// base class pointer
// MyClass* c2 = new MyClass("Doesn't work");
// this next line will give a compile error
// std::string* pstr = static_cast<MyClass*>(c2);
// delete c2;
}
Trying to sum-up all the discussions, it looks like you will never find a suitable dolution because ... your requirements are in cotraddiction.
You want you class to behave as ats::string
std::string behave as a value but
a value does not "change" when accessed but (think to c = a+b: do you expect a and b to change their value ??) ...
when accessing your "value" you want to change it.
If what I summed up collecting all the peaces (suggestion: edit your question otherwise all the answerer will risk to be lost) is correct you are in trouble with 3 & 4 (note the 3. derives from the concept of "assignment", and you can do noting to change it, while 4. comes from you directly)
Now, I can try to reverse-engineer your psychology (because you didn't provide good information about what your class represent and why you cannot "extend" a string) I can find
two possibility neither of which will fit all the above requirements.
Store a string into your class and make your class to behave as a std::string. There are threee ways to come to this point:
a. embed a string and make your class to decay to it:
essentially your class must contain
.
operator std::string&() { return my_string; } //will allow l-value assignments
operator const std::string&() const { return my_string; } //will allow r-value usage
const char* c_str() const { return my_string.c_str(); }
b. derive from std::string. In fact that's like having an anonymous my_string in it, which "decay" operations implicit. Not that different as above.
c. embed or privately derive, and rewrite the std::string interface delegating the std::string functions. It's just a long typing to get exactly the b. result. so what the f..k? (this last question is dedicated to all the ones that believe a. or b. will break encapsulation. c. will break it as well, it will only take longer!)
Don't store a string, but just get it as a result from a calculation (the "lookup" you talk about, not clarifying what it is).
In this last case, what you need is a class that decay automatically into std::string as a value.
So you need, in your class
operator std::string() const { return your_lookup_here; }
note that const is necessary, but there is no need to modify your class inner state, since the resulting string is not stored.
But this last solution has a problem with const char*: since the string is temporary, until you don't assign it, its buffer is temporary as well (will be destroyed) so decaying into const char* to assign the pointer is clueless (the pointer will point to a dead buffer).
You can have a
const char* c_str() const { return std::string(*this).c_str(); } //will call the previous one
but you can use this only into expressions or a pass-through parameter in function calls (since the temporary will exist until the evaluating expression is fully evaluated), not in an assignment towards an l-value (like const char* p; p = myclassinstace.c_str(); )
In all of the above cases (all 1.) you also need:
myclass() {}
myclass(const std::string& s) :my_string(s) { ... }
myclass(const char* s) :my_string(s) { ... }
or - in C++11, just
template<class ...Args>
myclass(Args&&... args) :my_string(std::forward<Args...>(args...)) {}
In case 2., instead of initialize the not existent my_sting, you should use the arguments to set what you will look up (we don't know what it is, since you did not tell us)
Hope in all these option you can find something useful.
You can add an operator const reference to string, as follows:
class C
{
public:
// Implicit conversion to const reference to string (not advised)
operator const std::string &() const
{
return s_;
}
// Explicit conversion to a const reference to string (much better)
const std::string &AsString() const
{
return s_;
}
private:
std::string s_;
};
As you can see from the comments, it would be much better to add an explicit conversion function if you really need this behavior. You can read about why this is bad in the Programming in C++ Rules and Recommendations article.

wrong argument conversion preferred when calling function

I'm writing a program under MS Visual C++ 6.0 (yes, I know it's ancient, no there's nothing I can do to upgrade). I'm seeing some behavior that I think is really weird. I have a class with two constructors defined like this:
class MyClass
{
public:
explicit MyClass(bool bAbsolute = true, bool bLocation = false) : m_bAbsolute(bAbsolute), m_bLocation(bLocation) { ; }
MyClass(const RWCString& strPath, bool bLocation = false);
private:
bool m_bAbsolute;
bool m_bLocation;
};
When I instantiate an instance of this class with this syntax: MyClass("blah"), it calls the first constructor. As you can see, I added the explicit keyword to it in the hopes that it wouldn't do that... no dice. It would appear to prefer the conversion from const char * to bool over the conversion to RWCString, which has a copy constructor which takes a const char *. Why does it do this? I would assume that given two possible choices like this, it would say it's ambiguous. What can I do to prevent it from doing this? If at all possible, I'd like to avoid having to explicitly cast the strPath argument to an RWCString, as it's going to be used with literals a lot and that's a lot of extra typing (plus a really easy mistake to make).
Explicit will not help here as the constructor is not a part of the implicit conversion, just the recipient.
There's no way to control the preferred order of conversions, but you could add a second constructor that took a const char*. E.g:
class MyClass
{
public:
MyClass(bool bAbsolute = true, bool bLocation = false);
MyClass(const RWCString& strPath, bool bLocation = false);
MyClass(const char* strPath, bool bLocation = false);
private:
bool m_bAbsolute;
bool m_bLocation;
};
Andrew Grant provided the solution. I want to tell you why it doesn't work the way you tried. If you have two viable functions for an argument, then the one that matches the argument best is called. The second requires a user-defined conversion, while the first only needs a standard conversion. That is why the compiler prefers the first over the second.
If you don;t want to keep casting it, then it seems to me that you might have to make another ctor that takes a const char*.
That is what I would probably do in this situation.
(Not sure why you are making a ctor with a type that you aren't passing for most of its use.)
edit:
I see someone else already posted this while I was typing mine
Not sure why it should confuse a reference to a string and a bool? I have seen problems with a bool and an int.
Can you lose the default value for the first constructor - it may be that since this is making it the default constructor for MyClass() then it is also the default if it can't match the args
Your choices are to add a constructor that explicitly takes a const char *
MyClass(const char* strPath, bool bLocation = false); // Thanks Andrew Grant!
Or do
MyClass( string("blah") );
The compiler intrinsically knows how to make a const char * into a bool. It would have to go looking to see if, for any of the first-argument types of MyClass constructors, there's a constructor that will take the source type you've given it, or if it can cast it to a type that is accepted by any of the constructors of any of the first-argument types of your MyClass constructors, or... well, you see where this is going and that's only for the first argument. That way lies madness.
The explicit keyword tells the compiler it cannot convert a value of the argument's type into an object of your class implicitly, as in
struct C { explicit C( int i ): m_i(i) {}; int m_i; };
C c = 10;//disallowed
C c( 2.5 ); // allowed
C++ has a set of rules to determine what constructor is to be called in your case - I don't know from the back of my head but you can intuitively see that the default arguments lead towards ambiguity.
You need to think those defaults through.
You can fallback onto some static, named, construction methods. Or you can use a different class (which is not a bad choice from a design viewpoint). In either way, you let the client code decide which constructor to use.
struct C {
static C fromString( const char* s, const bool b = true );
static C fromBools( const bool abs = true, const bool b = true );
};
or
struct CBase {
bool absolute;
bool location;
CBase( bool abs=true, bool loc=true );
};
struct CBaseFromPath {
// makes 'absolute' true if path is absolute
CBaseFromPath( const char* s, const bool loc );
};
Are you certain that it really is calling the first constructor? Are you calling it with the string hard-coded, or is it hidden behind a #define? Are you sure that the #define is what you think it is? (Try compiling with the /Ef option to get the expanded preprocessor output, and see if the call looks like you'd expect it to look.)
EDIT: Based on this and other comments, my suggestion is to add another constructor for const char*. Is that feasible?