I just learned about the std::optional feature in c++ 17 along with a few other very useful features...
but there is a few things that I don't understand about std::optional that I would like someone to explain them to me:
first of all as far as I know in std::optional the return value can either be the specified type or it can be nothing like this :
std::optional<std::string> getName()
{
if(person.hasName())
{
return person.name;
}
else
{
return {};
}
}
how does return {} returns nothing ? like for example if I was to make a similar class that return either the specified value or nothing, how do I make my own class so return {} is valid ? I'm I misunderstanding something here ?
my second question is that when you want to check the return value you can either do :
int main()
{
std::optional<std::string> name = getName();
if(name.has_value()) // check if the name is valid using the has_value function
{
...
}
}
or i can also do :
int main()
{
std::optional<std::string> name = getName();
if(name) // check if the name is valid only using the variable name ???
{
...
}
}
I'm really confused about this how could a variable name return a boolean ? not like the constructor of an object can return anything, so how is this possible ?
again let's say I want to make my own class that is kind of similar to std::optional how do I make it so an instance of my class can be used as a boolean ?
I would really appreciate answers that adress my questions and not something related to when to use std::optional or why I shouldn't make my own class that does the same thing etc...
thanks!
return {};
will simply call the default constructor of the class.
By giving the class a conversion operator to bool it can be implicitly converted to a bool when needed.
It would look something along the lines of
template <typename T>
class optional {
public:
optional() {}
optional(T t) : has_value(true), value(std::move(t)) {}
operator bool() {
return has_value;
}
private:
bool has_value = false;
T value;
}
Very simplified, missing assignement operators and more.
how do I make my own class so return {} is valid ?
By making the class default constructible. Exactly how to do that depends on the class. In cases where the class is implicitly default constructible you need to do nothing, while in other cases you may need to explicitly declare the constructor. Like this for example: ClassName() = default;.
how could a variable name return a boolean
Think about how this variable name "returns a boolean":
int x = 42;
if (x)
;
Or how this variable name "returns a std::string_view":
const char* str = "example";
std::string__view sv = str;
This is called a conversion from one type to another. That is what happens in if(name).
how do I make it so an instance of my class can be used as a boolean ?
By providing a conversion operator.
Related
How do you make a class for example return a member variable when it is called? Say:
class Person {
std::string name;
// Constructor and Destructor go here..
};
Person mike = "Mike";
// /!\ How do you make "mike" return "Mike" directly when the object mike is called?
// This is the same thing like an int return its value and a vector returns its members (scalars)
std::string name = mike;
Additional Edit: The cast operator is not a good option here as it ruins the way a type is written. For example std::string name = static_cast<string>(mike); is a horrible way to achieve my target.
You're looking for a conversion operator, which is written like this:
class Person {
std::string name;
public:
Person(char const * name) : name(name) {}
operator std::string () const { return name; }
};
Here's a demo.
You could also make the conversion operator a template, like this:
template<typename T>
operator T() const { return name; }
Here's a demo.
I am trying to implement lazy initializing in C++ and I am searching for a nice way to call the Initialize() member function when some other method like object->GetName() gets called.
Right now I have implemented it as follows:
class Person
{
protected:
bool initialized = false;
std::string name;
void Initialize()
{
name = "My name!"; // do heavy reading from database
initialized = true;
}
public:
std::string GetName()
{
if (!initialized) {
Initialize();
}
return name;
}
};
This does exactly what I need for the time being. But it is very tedious to setup the initialized check for every method, so I want to get rid of that. If someone knows a nice way in C++ to improve this above example, I would like to know!
Could maybe operators be used to achieve calling Initialize() when using -> for example?
Thanks!
Sounds like a job for templates! Create a lazily_initialized wrapper that takes a type T and a function object TInitializer type:
template <typename T, typename TInitializer>
class lazily_initialized : TInitializer
{// ^^^^^^^^^^^^^^
// inheritance used for empty-base optimization
private:
T _data;
bool _initialized = false;
public:
lazily_initialized(TInitializer init = {})
: TInitializer(std::move(init))
{
}
T& get()
{
if(!_initialized)
{
static_cast<TInitializer&>(*this)(_data);
_initialized = true;
}
return _data;
}
};
You can the use it as follows:
struct ReadFromDatabase
{
void operator()(std::string& target) const
{
std::cout << "initializing...\n";
target = "hello!";
}
};
struct Foo
{
lazily_initialized<std::string, ReadFromDatabase> _str;
};
Example:
int main()
{
Foo foo;
foo._str.get(); // prints "initializing...", returns "hello!"
foo._str.get(); // returns "hello!"
}
example on wandbox
As Jarod42 mentioned in the comments, std::optional<T> or boost::optional<T> should be used instead of a separate bool field in order to represent the "uninitialized state". This allows non default-constructible types to be used with lazily_initialized, and also makes the code more elegant and safer.
As the former requires C++17 and the latter requires boost, I used a separate bool field to make my answer as simple as possible. A real implementation should consider using optional, using noexcept where appropriate, and also consider exposing a const-qualified get() that returns a const T&.
Maybe call it in the constructor?
Edit: Uh, i missed the point of your question sorry.
What about a lazy factory initialization?
https://en.wikipedia.org/wiki/Lazy_initialization#C.2B.2B
I am trying to figure out this assignment from my level 2 class.
We are to create a class called Number, derived from std::string.
the only code in this class is to be two constructors, a default and one that takes a string as an arguement.
I have:
class Number : public string {
public:
Number();
Number(string set);
}
The constructors are then coded as:
Number::Number() : string("0") { } // default constructor sets data string to "0"
Number::Number(string set) : string(set) { }
So far so good. Then we are to take two classes that we have been developing, Double and Integer, and derive them from Number. Within these two classes we used to have a double and an int respectively as the data member. Now, because of inheritance, we are supposed to have a built in data section (string). The issue that I am having is that all of my operator=() overloads are now "recursive on all paths" leading to a stackoverflow at runtime. I will show an example of the Double constructor that takes a string, and the equals function that causes the infinite recursion.
Double::Double(string d) : Number(d)
{
// overloaded constructor that takes a string argument
if (isNaN(d)) {
*this = "0.0";
}
else {
*this = d;
}
// used for setting the value of a data member with a string
void Double::operator=(string d)
{
if (isNaN(d)) {
*this = "0.0";
}
else {
*this = d;
}
}
}
I see where the recursion is happening as *this is calling the overloaded = which calls itself since I am using *this in the = function itself. So what would the proper syntax be for setting the data member to a supplied value. Before it was just this->dataMemberName = supplied value of proper type.
It should be noted that my non-string constructors do set the value of an instanced object:
Double::Double(int d) : Number(to_string(d)){}
but the second I try to do anything with them, + - * /, the = function is called and then the error happens again.
Just add:
using std::string::operator=;
Abbreviated example:
#include <string>
class Number : public std::string {
public:
};
class Double : public Number {
public:
using std::string::operator=;
Double()
{
*this="0.0";
}
};
After discussion in comments I decided to rewrite my answer so that it is more clear what I mean.
You should just call the base class operator= and let it handle member assignment.
You have class Number defined like this:
class Number : public string {
public:
Number();
Number(string set);
};
Can this class work for us, as we want it without any modifications? Let's look.
First thing we need is operator= in base class.
operator= is neither declared, nor deleted in class Number which means that if you call Number& Number::operator=(Number const&) this function will be generated for you by compiler. So we are good here.
Second thing which is important for my solution to work is conversion from std::string to Number.
There is constructor Number::Number(std::string) in class Number. Fortunately it's not declared explicit co it can be used implicitly (with explicit constructor it would be more verbose, but also possible). Compiler will use this constructor when it needs to convert std::string into Number. One-parameter constructors are sometimes called converting constructors.
Ok, so we have second requirement fulfilled.
That's all we need from base class!
Now to work.
We begin with creation of a helper function:
std::string check_for_NaN(std::string s)
{
if(isNaN(s)) { return "0.0"; }
return s;
}
Now we can simplify Double's constructor:
Double::Double(std::string s): Number(check_for_NaN(s)) //no magic here
{}
And we can create our long awaited operator= for class Double:
Double& operator=(std::string rhs)
{
Number::operator=(check_for_NaN(rhs)); //here we have magic, explained below
//if Double has some members of its own, copy them here
return *this;
}
So, what happens when we call 'Number::operator=(check_for_NaN(rhs));'?
check_for_NaN(rhs) returns us proper string object.
Compiler looks for Number::operator=(std::string) but can't find it.
It finds that it can generatr Number::operator=(const Number&)!
Compiler checks it such an operator would help.
It would if we could convert std::string to Number.
But we can! There is Number::Number(std::string) constructor that is not explicit!
Compiler generates assignment operator.
From std::string rhs it creates a temporary object of class Number.
Calls generated operator.
We are all happy because it worked!
You can specify directly that you want to use std::string's operator=:
#include <string>
using namespace std;
class Number : public string
{
public:
Number();
Number(string set);
};
Number::Number() : string("0") {}//default constructor sets data string to "0"
Number::Number(string set) : string(set) {}
class Double : public Number {
public:
//using Number::operator=;
Double(string d);
void operator=(string d);
double val;
};
bool isNaN(string d) { return false; }
Double::Double(string d) : Number(d) {//overloaded constructor that takes a string argument
if(isNaN(d))
{
string::operator=("0.0");
}
else
{
string::operator=(d);
}
}
void Double::operator=(string d)//used for setting the value of a data member with a string
{
if(isNaN(d))
{
string::operator=("0.0");
}
else
{
string::operator=(d);
}
}
int main()
{
Double d("3");
d = "4";
return 0;
}
I have to create a template function that searches an element in a map variable. If the element exists, the function must return it. Otherwise it must return NULL.
template <class K, class E> E dictionary<K,E>::research(K key) {
// map<K,E> elements;
if(elements.find(key) != elements.end()) {
return elements.find(key)->second;
} else {
return NULL;
}
Since the return type is E, returning NULL gives me always an error. How can I make this work? Or I have to structure my function differently?
This is a school homework assignment and I must return NULL, no alternatives. I'd personally do differently if I could.
The design of this function is incorrect. It is perfectly possible that NULL is simply incompatible with the type E. For instance, suppose that E is a struct, or a std::string and so on.
This is a school homework assignment and I must return NULL, no alternatives.
Either your homework assignment is incorrect, or you have misunderstood its requirements. It is possible that you are expected to return a pointer to E?
Instead of returning pointers, you could consider returning something like boost::optional, i.e. a type that is either set to contain a valid object or in an invalid state. That mimics a pointer in some way, but is more explicit
The following is just to show the principle, the implementation can for sure be optimized.
template<typename T> class Optional {
public:
Optional(E e):
isValid(true),
mValue(e)
{}
Optional(): isValid(false), mValue() {}
bool isDefined() const {return isValid;}
E getOrElse(E const& other) const {return (isValid) ? (mValue) : (other);}
E get(E const {return mValue;}
private:
bool isValid;
T mValue;
};
Following is a popular code:
class A
{
public:
static const string TYPE = "AEvent";
const string& getType() { return TYPE; }
};
Above code could be use like this:
if (aInstance.getType() == A::TYPE)
{
...
}
It's fine. But it's not intuitiveness. Did not? Look at the next code:
class A
{
public:
static const string& getType()
{
static const string TYPE = "AEvent";
return TYPE;
}
}
//Usage
if (aInstance.getType() == A::getType())
....
Of course, getType is static method but it's possible to access dot operator and It's more intuitively see to me.
How do you think about?
If it's clearer to use obj.static_member (or method), then use it; this is often true when the type name is long, such as with templates. Otherwise use Type::static_member.
As long as you're returning a static variable from static method it should be fine. It doesn't matter if you call it using dot or resolution operator. Either way it's part of the object as well as the class which should give you the same static variable.