Meaning of "const -> std::string const&" after the function definition? - c++

Reading the answer for one exercise in C++ Primer, 5th Edition, I found this code:
#ifndef CP5_ex7_04_h
#define CP5_ex7_04_h
#include <string>
class Person {
std::string name;
std::string address;
public:
auto get_name() const -> std::string const& { return name; }
auto get_addr() const -> std::string const& { return address; }
};
#endif
What does
const -> std::string const&
mean in this case?

auto get_name() const -> std::string const& { return name; } is trailing return type notation for the equivalent
std::string const& get_name() const { return name; }
Note that the equivalence is exact in the sense that you can declare a function using one syntax and define it with the other.
(This has been part of the C++ standard since and including C++11).

The part -> std::string const& is trailing return type and is new syntax since C++11.
The first const says it a const member function. It can be safely called on a const object of type Person.
The second part simply tells what the return type is - std:string const&.
It is useful when the return type needs to be deduced from a template argument. For known return types, it is no more useful than than using:
std::string const& get_name() const { return name; }

It all makes more sense when you see an example where it actually matters; as written in the question, it's just an alternative way to declare the return type.
If you have a template function where you can not know the return type in advance, this can actually help. For example:
template <class X, class Y> auto DoSomeThing(X x, Y y) -> decltype(x * y);
You don't know what types X and Y actually are but you know the return value will have the same type as x * y which can be deduced in this way.

const is a cv-qualifier of the usual kind for the member function : *this is const inside the function.
-> std::string const& pairs with auto to form a trailing return type (see (2)). The difference is only syntactic here -- the following syntax is equivalent:
std::string const& get_name() const { return name; }

Related

Use std::variant as class member and apply visitor

I'm trying to use std::variant as a class member variable and then use operator overloading so that the two Variants of this class can use the operator plus to produce a new variable. The problem is that std::get does not work as I thought and so I cannot retrieve the correct (hardcoded) string types so that the AddVisitor struct is used.
I get a compilation error that says: no matching function for call to ‘get<0>(std::basic_string&)’
Also is there a way that operator+ function detects the type without if-else statements?
I have already checked a lot of answers in SO including ones that answer questions about similar Boost functionality, but I cannot get it to work.
#include <iostream>
#include <variant>
#include <string>
#include "stdafx.h"
using Variant = std::variant<int, std::string>;
template<typename T>
struct AddVisitor
{
T operator()(T v1, T v2)
{
return v1 + v2;
}
};
class Var
{
Variant v;
public:
template<typename T>
Var(T value) : v(value) {}
Var operator+(Var& val)
{
// PROBLEM: This is a hard coded example that I want to use, so that concatenation of two strings happens.
return std::visit(AddVisitor<std::string>(), std::get<std::string>(v), std::get<std::string>(val.get()));
// Is there a way to get the correct type without if-else statements here?
}
Variant get()
{
return v;
}
};
int main()
{
Var x("Hello "), y("World");
// The expected output is this:
Var res = x + y;
return 0;
}
I expect to be able to use the plus operator and concatenate two strings or two integers and create a new Var variable.
Ok, so there are a few things to talk about.
First, the visitor for std::visit with more than one variant argument should accept all combinations of variant types. In your case it should accept:
(string, string)
(string, int)
(int, int)
(int, string)
If for you only string, string and int, int are valid you still need to accept the other combinations for the code to compile, but you can throw in them.
Next, the visitor shouldn't be templated. Instead the operator() should be templated or overloaded for all the above combinations.
So here is AddVisitor:
struct AddVisitor
{
auto operator()(const std::string& a, const std::string& b) const -> Variant
{
return a + b;
}
auto operator()(int a, int b) const -> Variant
{
return a + b;
}
// all other overloads invalid
template <class T, class U>
auto operator()(T, U) const -> Variant
{
throw std::invalid_argument{"invalid"};
}
};
It's not clear from documentation what the overloads can return, but I couldn't make it compile unless all return Variant. Fortunately the compiler errors are TREMENDOUSLY HELPFULL . (I need to check the standard).
Next, when you call std::visit you need to pass the variants you have.
So the final code is this:
auto operator+(Var& val) -> Var
{
return std::visit(AddVisitor{}, get(), val.get());
}
And you can indeed use it like you want:
Var res = x + y;
Another issue with your code is that get makes unnecessary copies. And copies of std::variant are not cheap to make. So I suggest:
auto get() const -> const Variant& { return v; }
auto get() -> Variant& { return v; }

What is the difference between const string & str and string const & str when passed as an argument to a function in c++

I am using pass by reference to const string in a function argument like below:
class Super
{
void alignment(const string & str);
};
void Super::alignment(const string & str)
{
//do some stuff
}
Now if I use as below it gives the same result:
void Super::alignment(string const & str)
{
//do some stuff
}
What is the difference in this two types of definition in c++?
const T& and T const& are semantically the same exact thing. Just like const T* and T const* are semantically the same, but T const* and T* const are different.
the const keyword is left associative, but in "const string &str", since there's no left keyword to qualify, it apply to the word at his right (so string).
It is the same but it's not parsed the same.

Is there "modern" way to avoid this kind of code duplication

I have C++ class similar to this:
class A{
std::string str;
public:
A(std::string &str) : str(str){}
int cmpAt(const std::string &key) const{
return str.cmp(key);
}
int cmpAt(const char *key) const{
return str.cmp(key);
}
}
Both cmpAt methods look the same. Is there some way NOT to duplicate the method? Perhaps with template ?
You should just write a function template:
template <typename K>
int cmpAt(K const& key) const {
return str.compare(key);
}
That way, if you call cmpAt with a const char*, you can avoid the overhead of having to construct an extra std::string.
EDIT Never mind, you're out of luck:
int compare(const charT* s) const;
5 Returns: compare(basic_string(s)).
So just delete the const char* overload - it provides you nothing of extra value over the std::string const& overload. You would have to write your own compare function to avoid the extra string constructor, at which point it's not code duplication anymore.
I would use boost::string_ref or your favourite other implementation of it
class A{
std::string str;
public:
A(std::string &str) : str(str){}
int cmpAt(const boost::string_ref &key) const{
return key.compare(str) * -1;
}
}
This will not create temporary strings and you can pass string literals and std::string.
When int cmpAt(const std::string &key) is called with const char*, key will be constructed with const char*. so you can simply delete cmpAt(const char *key).
As others have correctly pointed out, in your specific case, there's no need for a non-const comparison function.
However, in the general case, you can do the following:
RetType someMethod(params...) const {
return LongAndComplexComputation(params, ...);
}
// Return type deduction is C++14.
// If you can't use C++14, only C++11, the return type should be:
// const std::remove_reference<decltype(*this)>::type *
auto cthis() const {
return this;
}
RetType someMethod(params...) {
return cthis()->someMethod(params, ...)
}
If necessary, you will have to cast away const-qualification from the return type (e.g. when you are returning a pointer inside *this), using const_cast.

Overwrite Cast Operator in C++

As a C++ beginner I want to write some simple type casts. It there a way to create casting logic which can be used in the type new = (type)old format with the prefix parentheses?
string Text = "Hello";
char* Chars = "Goodbye";
int Integer = 42;
string Message = Text + (string)Integer + (string)Chars + "!";
I'd like to stick with this syntax if possible. For example the string cast of boost int Number = boost::lexical_cast<int>("Hello World") has an unattractive long syntax.
Just use a normal function that you overload for different types:
std::string str(int i) {
return "an integer";
}
std::string str(char* s) {
return std::string(s);
}
Then use if not like a cast, but as a normal function call:
string Message = Text + str(Integer) + str(Chars) + "!";
It's the most common thing in C++ to cast using a NAME<TYPE>(ARGUMENT) syntax, like in static_cast<int>(char). It makes sense to extend this the way boost does.
However, if you want to convert non-primitive types, you can use non-explicit constructors with a single argument and the cast operator.
class MyType {
public:
MyType(int); // cast from int
operator int() const; // cast to int
};
This is not possible if you are dealing with already existing types.
You cannot change the behaviour of the C-style cast. C++ will make up its mind how to interpret such a cast.
You could however come up with an intermediate type that shortens the syntax:
template <typename From>
struct Cast {
From from;
Cast(From const& from) : from(from) {}
template <typename To>
operator To() const {
return convert(from,To());
}
};
template <typename From>
Cast<From> cast(From const& from) {
return Cast<From>(from);
};
std::string convert(int, std::string const&);
This would allow you to convert things explicitly but without stating how exactly:
int i = 7;
std::string s = cast(i);

What is the effect of `const` modifier and reference in the template argument of std::function

I am not sure about the effect of const modifier and reference in the template argument of std::function. For example, in the following codes, should I use std::function<bool(std::string, std::string)> or std::function<bool(const std::string&, const std::string&)> as the base class ? I tested both in GCC 4.4, however, there was no difference. Thanks in advance.
#include <iostream>
#include <functional>
#include <string>
//struct FLess : public std::function<bool(std::string, std::string)>
struct FLess : public std::function<bool(const std::string&, const std::string&)>
{
bool operator () (const std::string& s1, const std::string& s2) const
{
return s1 < s2;
}
};
int main(int argc, char* argv[])
{
FLess f;
std::string a = "a";
std::string b = "b";
std::cerr << f(a, b) << std::endl;
return 0;
}
You are not supposed to inherit from std::function.
Rather you use to abstract the underlying kind of function object like this:
void DoSomething(function<void(const string&, const string&) myF)
{
string s1, s2;
myF(s1, s2);
}
// usage:
DoSomething(bind(otheFunc, ....));
DoSomething([](const string& s1, const string& s2) { ... });
struct Func
{
operator()(const string& s1, const string& s2)
{ ... }
}
Func f;
DoSomething(f);
Now to answer your question, if you use const string& you are asking the compiler not to copy the object and to forbid modifications. That choice depends on the meaning you are giving to your parameters.
For small types like numbers and small struct, pass by copy.
Unless you want to perform very advanced copy/move optimizations, you'd better always use const& for large types. I'd consider string a large type, unless you are sure that it will never grow.
It boils down to compatibility between the function object's parameter types and those of the callable entity it is referring to, if the function's parameter types can be converted to the callable entities parameter types or not:
void foo(double x, double y);
void bar(const double& x, const double& y);
void fooBar(double& x, double& y);
std::function<void(const double&, const double&)> f;
f = &foo; // OK
f = &bar; // OK
f = &fooBar; // Error on GCC 4.7. Cannot instantiate a double& from const double.
Interestingly, an std::function with void return type is compatible with callable entities with any return type:
int fooBarFoo(const double& x, const double& y);
f = &fooBarFoo; // OK
So in your case, where you are comparing passing by const reference as opposed to passing by value, I think there is no observable difference.
Passing a reference to a const object avoids making a copy of the object just to pass to the function. In your case (a tiny string) it probably doesn't make enough difference to notice.
If you were dealing with a string of (say) several megabytes, passing by reference to const would avoid allocating space for (and copying) all that data.
At the same time, most compilers internally implement references pretty much like pointers. This can lead to slower execution because of an extra level of indirection. For small items (char, int, probably long) you usually prefer to pass by value. For larger items (potentially long strings, matrices, etc.) you usually prefer to pass by reference. If in doubt, usually pass by reference -- the penalty for being wrong in this direction is generally fairly small.