The difference between const auto& vs as_const? - c++

Basically, I'm trying to learn about C++ 17, and I found as_const.
What's the difference when we use:
MyType t;
auto& p = as_const(t);
instead of:
MyType t;
const auto& p = t;
Are there some advantages here?

In your case they are the same.
std::as_const is usually used to select the const version from a set of overloaded (member) functions. The following is an example from cppreference.
struct cow_string { /* ... */ }; // a copy-on-write string
cow_string str = /* ... */;
// for(auto x : str) { /* ... */ } // may cause deep copy
for(auto x : std::as_const(str)) { /* ... */ }
Even if you use for(const auto &x : str), a deep copy may still happen.

In the simple case of assigning to a reference, I doubt either option has any objective benefit over the other. Personally I prefer seeing the const attached to the variable but that's entirely subjective.
as_const() has one important benefit: it can be used to force constness without requiring a variable declaration. E.g., when calling a method where the constness of the parameter matters:
#include <iostream>
#include <utility>
void example(int const & i) {
::std::cout << "const int" << ::std::endl;
}
void example(int & i) {
::std::cout << "int" << ::std::endl;
}
int main() {
int i = 5;
example(i); // Prints "int"
example(::std::as_const(i)); // Prints "const int"
}

Related

How to make a data member const after but not during construction?

Without relying on const_cast, how can one make a C++ data member const after but not during construction when there is an expensive-to-compute intermediate value that is needed to calculate multiple data members?
The following minimal, complete, verifiable example further explains the question and its reason. To avoid wasting your time, I recommend that you begin by reading the example's two comments.
#include <iostream>
namespace {
constexpr int initializer {3};
constexpr int ka {10};
constexpr int kb {25};
class T {
private:
int value;
const int a_;
const int b_;
public:
T(int n);
inline int operator()() const { return value; }
inline int a() const { return a_; }
inline int b() const { return b_; }
int &operator--();
};
T::T(const int n): value {n - 1}, a_ {0}, b_ {0}
{
// The integer expensive
// + is to be computed only once and,
// + after the T object has been constructed,
// is not to be stored.
// These requirements must be met without reliance
// on the compiler's optimizer.
const int expensive {n*n*n - 1};
const_cast<int &>(a_) = ka*expensive;
const_cast<int &>(b_) = kb*expensive;
}
int &T::operator--()
{
--value;
// To alter a_ or b_ is forbidden. Therefore, the compiler
// must abort compilation if the next line is uncommented.
//--a_; --b_;
return value;
}
}
int main()
{
T t(initializer);
std::cout << "before decrement, t() == " << t() << "\n";
--t;
std::cout << "after decrement, t() == " << t() << "\n";
std::cout << "t.a() == " << t.a() << "\n";
std::cout << "t.b() == " << t.b() << "\n";
return 0;
}
Output:
before decrement, t() == 2
after decrement, t() == 1
t.a() == 260
t.b() == 650
(I am aware of this previous, beginner's question, but it treats an elementary case. Please see my comments in the code above. My trouble is that I have an expensive initialization I do not wish to perform twice, whose intermediate result I do not wish to store; whereas I still wish the compiler to protect my constant data members once construction is complete. I realize that some C++ programmers avoid constant data members on principle but this is a matter of style. I am not asking how to avoid constant data members; I am asking how to implement them in such a case as mine without resort to const_cast and without wasting memory, execution time, or runtime battery charge.)
FOLLOW-UP
After reading the several answers and experimenting on my PC, I believe that I have taken the wrong approach and, therefore, asked the wrong question. Though C++ does afford const data members, their use tends to run contrary to normal data paradigms. What is a const data member of a variable object, after all? It isn't really constant in the usual sense, is it, for one can overwrite it by using the = operator on its parent object. It is awkward. It does not suit its intended purpose.
#Homer512's comment illustrates the trouble with my approach:
Don't overstress yourself into making members const when it is inconvenient. If anything, it can lead to inefficient code generation, e.g. by making move-construction fall back to copy constructions.
The right way to prevent inadvertent modification to data members that should not change is apparently, simply to provide no interface to change them—and if it is necessary to protect the data members from the class's own member functions, why, #Some programmer dude's answer shows how to do this.
I now doubt that it is possible to handle const data members smoothly in C++. The const is protecting the wrong thing in this case.
Something along these lines perhaps:
class T {
private:
T(int n, int expensive)
: value{n-1}, a_{ka*expensive}, b_{kb*expensive} {}
public:
T(int n) : T(n, n*n*n - 1) {}
};
One possible way could be to put a and b in a second structure, which does the expensive calculation, and then have a constant member of this structure.
Perhaps something like this:
class T {
struct constants {
int a;
int b;
constants(int n) {
const int expensive = ... something involving n...;
a = ka * expensive;
b = kb * expensive;
}
};
constants const c_;
public:
T(int n)
: c_{ n }
{
}
};
With that said, why make a_ and b_ constant in the first place, if you control the class T and its implementation?
If you want to inhibit possible modifications from other developers that might work on the T class, then add plenty of documentation and comments about the values not being allowed to be modified. Then if someone modifies the values of a_ or b_ anyway, then it's their fault for making possibly breaking changes. Good code-review practices and proper version control handling should then be used to point out and possibly blame wrongdoers.
Before describing the answer, I'd first suggest you to re-think your interface. If there's an expensive operation, why don't you let the caller be aware of it and allow them to cache the result? Usually the design forms around the calculations and abstractions that are worth keeping as a state; if it's expensive and reusable, it's definitely worth keeping.
Therefore, I'd suggest to put this to the public interface:
struct ExpensiveResult
{
int expensive;
ExpensiveResult(int n)
: expensive(n*n*n - 1)
{}
};
class T
{
private:
const int a;
const int b;
T(const ExpensiveResult& e)
: a(ka * e.expensive)
, b(kb * e.expensive)
{}
};
Note that ExpensiveResult can be directly constructed from int n (ctor is not explicit), therefore call syntax is similar when you don't cache it; but, caller might, at any time, start storing the result of the expensive calculation.
It's pretty easy to modify the const ints in your object as a result of a significant change in c++20. The library function construct_at and destroy_at have been provided to simplify this. For your class, destroy_at is superfluous since the class contains no members that use dynamic memory like vector, etc. I've made a small modification, added a constructor taking just an int. Also defined an operator= which allows the objects to be manipulated in containers. You can also use construct_at to decrement a_ and b_ in your operator-- method. Here's the code:
#include <iostream>
#include <memory>
namespace {
constexpr int initializer{ 3 };
constexpr int ka{ 10 };
constexpr int kb{ 25 };
class T {
private:
int value;
const int a_{};
const int b_{};
public:
T(int n);
T(int n, int a, int b);
T(const T&) = default;
inline int operator()() const { return value; }
inline int a() const { return a_; }
inline int b() const { return b_; }
int& operator--();
T& operator=(const T& arg) { std::construct_at(this, arg); return *this; };
};
T::T(const int n, const int a, const int b) : value{ n - 1 }, a_{ a }, b_{ b } {}
T::T(const int n) : value{ n - 1 }
{
// The integer expensive
// + is to be computed only once and,
// + after the T object has been constructed,
// is not to be stored.
// These requirements must be met without reliance
// on the compiler's optimizer.
const int expensive{ n * n * n - 1 };
std::construct_at(this, n, ka*expensive, kb*expensive);
}
int& T::operator--()
{
// implement decrements
//--a_; --b_;
const int a_1 = a_ - 1;
const int b_1 = b_ - 1;
std::construct_at(this, value, a_1, b_1);
return value;
}
}
int main()
{
T t(initializer);
std::cout << "before decrement, t() == " << t() << "\n";
--t;
std::cout << "after decrement, t() == " << t() << "\n";
std::cout << "t.a() == " << t.a() << "\n";
std::cout << "t.b() == " << t.b() << "\n";
return 0;
}
Output:
before decrement, t() == 2
after decrement, t() == 1
t.a() == 259
t.b() == 649

const reference to temporary variable does not work for std::function whose type does not match its declaration

class Context {
public:
Context(){
field2values_["age"] = std::vector<int>{1,2,3};
}
const std::vector<int>& field2values(const std::string& field) const {
auto it = field2values_.find(field);
if (it == field2values_.end()) {
return default_ints_;
}
return it->second;
}
private:
std::map<std::string, std::vector<int>> field2values_;
std::vector<int> default_ints_;
};
Context ctx;
std::vector<int> ctx_field2values(const std::string& field) {
return ctx.field2values(field);
}
class Checker {
public:
explicit Checker():
user_field_values_(ctx_field2values),
user_field_values_nc_(ctx_field2values)
{}
void print(){
const auto& values = user_field_values_("age");
std::cout << "size=" << values.size() << std::endl; // unexpected: 18446744073709535740
const auto& values_nc = user_field_values_nc_("age");
std::cout << "size=" << values_nc.size() << std::endl; // expected: 3
}
private:
const std::function<const std::vector<int>&(const std::string&)> user_field_values_;
const std::function<std::vector<int>(const std::string&)> user_field_values_nc_;
};
int main() {
Checker checker;
checker.print();
}
As we all know, const reference to temporary variable will extend the its lifetime. But in the code above, it does not work for user_field_values_ while it works for user_field_values_nc_. I guess this is because the type of user_field_values_ does not match its initialization, namely ctx_field2values. But why is there such a difference? Can anyone explain in principle why this rule (const reference to temporary variable) does not take effect?
Thanks in advance.
It's the same reason the following produces a dangling reference:
int f() {
return 42;
}
const int& invoke_f() {
return f();
}
const auto& e = invoke_f(); // dangling!
Basically, when a temporary appears in a return statement, its lifetime is not extended. It gets destroyed at the end of the return statement. ([class.temporary]/(6.11))
The function call operator of user_field_values_ behaves just like the invoke_f above. It invokes ctx_field2values (which returns a vector<int>), and returns the result as a const vector<int>& -- a dangling reference.
In C++23, std::function will be able to recognize this pattern (by means of std::reference_converts_from_temporary) and reject it. But it requires compiler support, which AFAIK does not exist yet.

Generic "sqr" function

I'm trying to figure out how to write "fully generic function" for sqr operation (it's actually can be multiply, division, add, does not really matter).
Consider the following code
#include <iostream>
struct A
{
int val = 2;
A() = default;
A(const A&) = delete; // To make sure we do not copy anything
A(A&& a) = delete; // To make sure we do not move anything
auto operator=(auto) = delete; // To make sure we do not assign anything
// This is important part, we do not want to create a new object on each multiplication.
// We want just to update the old one.
A& operator*(const A& a)
{
val *= a.val;
return *this;
}
};
// Just for easy printing (you can ignore it).
std::ostream &operator<<(std::ostream &os, const A& a) {
return os << a.val;
}
// Here auto&& represents forwarding reference and should automatically understand whether input r or l value.
auto&& sqr(auto&& val)
{
return val * val;
}
int main()
{
A a;
std::cout << sqr(a) << "\n"; // OK
std::cout << sqr(A()) << "\n"; // OK
std::cout << sqr(1) << "\n"; // Wrong, ref to local returned
int i = 2;
std::cout << sqr(i) << "\n"; // Wrong, ref to local returned
}
sqr function here is meant to be sort of generic stuff, it should handle all possible situations (r-values, l-values) and for object a it's actually does, but not for i. I can't get why it's trying to return reference instead of copy. Could anyone please shed some light on the situation? Is there any way I can accomplish this task easily (with one template function ideally)? I can use c++ 20 standard if necessary.
auto&& sqr(auto&& val)
{
return val * val;
}
sqr above always returns a reference. But returning a reference to a local is always wrong. Let the return-type deduce to a non-reference by using auto instead.
constexpr // May be constexpr for some types
auto sqr(auto&& x) // return type is non-reference or trailing
noexcept(noexcept(x*x)) // propagate noexcept
-> decltype(x*x) // enable SFINAE
{ return x * x; }

const method modifies object using reference

The following code calls a const method passing a reference to a member, which is then modified.
#include <iostream>
struct A {
int i;
A(int _x) : i(_x) { }
void calc(int& j, const int value) const { j = value; }
void set1() { calc(i, 1); }
};
int main()
{
A a(3);
std::cout << a.i << std::endl;
a.set1();
std::cout << a.i << std::endl;
return 0;
}
The code compiles with gcc 6.4.0, and with clang 5.0.2, with no warnings.
Is the code legal?
The const method calc is able to modify the object, when called from a non-const method.
const qualifier on a member function applies to the *this instance.
In calc(), this is a pointer to const A, but the parameter j is taken by non-const reference, so this is perfectly standard behaviour.
Now, if in calc you tried to assign to this->i, the code would not compile.
void A::calc(const int value) const
{
i = value; // Compilation error here: i is a data member of a const instance
}
In the same way, if set1 was made a const member function, then, the code would not compile (because it would try to bind this->i to a parameter taken by non-const reference)
Sure. Marking the method const just makes *this const, i.e. the function promises not to modify the object by writing through this.
It's still possible to modify the object through other means (assuming they're not marked const as well, such as int& j in your example).
Remember that having a "const pointer" like const Thing* or a "const reference" like const Thing& does NOT mean that the const-qualified object cannot change while you have the pointer/reference. It only means that you can't use that particular pointer/reference as a way of changing it. But there could be other names, pointers, or references that do allow changing it.
A couple of examples:
void f1(const int& arg1, int& arg2) {
std::cout << "arg1 before: " << arg1 << "\n";
arg2 = 4;
std::cout << "arg1 after: " << arg1 << "\n"; // same thing?
}
f1 might look as though it must always print the same value in the "before" and "after" lines. But not if someone passes the same int object to both arguments:
void call_f1() {
int n = 7;
f1(n, n); // Prints before 7, after 4!
}
Or if a function call comes between two uses of a const reference, that can similarly change a variable in some way:
void something_else();
void f2(const int& arg) {
std::cout << "arg before: " << arg << "\n";
something_else();
std::cout << "arg after: " << arg << "\n";
}
int n = 2;
void something_else() { n = 8; }
void call_f2() {
f2(n); // Prints before 2, after 8!
}
So it's true that in your void A::calc(int& j, const int value) const function, the this pointer is const A* const, which means you can't change the A object using the this pointer. But there can still be other ways to change it, like here you have an int& j reference to non-const object. If it so happens that j refers to a subobject of *this, then modifying j is a valid way of modifying the subobject of *this. This is similar to my f1 example above, where arg1 can't be used to change the referenced int, but arg2 can, and if they refer to the same int, this means arg1 has changed.
The case is slightly different when a variable is defined with the const qualifier in the first place. If we write
const A a(3);
then we do get a guarantee that (except during the constructor and destructor), the object can't be changed in any way. The language will usually prevent you from accidentally trying, like with a.set1(), but even if you try const_cast tricks, any actual change would then be undefined behavior.
There is nothing wrong with your code. Declaring a method const merely means that this is const. However, your method does not (directly) modify this or any members of this. Consider this contrived, albeit correct example:
struct foo {
int value;
void modify_const(foo& f) const { f.value = 5; }
};
int main() {
foo f;
f.value = 3;
f.modify_const(f);
}
The method does not modify this, and the parameter is declared as non-const, thus calling f.modify_const(f); on a const f will fail due to the parameter being passed as non-const.
Just shows you are never safe. A const qualifier doesn't guarantee the value can never change.
Try it like this, and you can do really nasty things:
#include <iostream>
class A {
const int i;
void calc(int& j, const int value) const { j = value; }
public:
A(int _x) : i(_x) { }
void set1() const { calc(*const_cast<int*>(&i), 1); }
int getI() const { return i; }
};
int main()
{
const A a(3);
std::cout << a.getI() << std::endl;
a.set1();
std::cout << a.getI() << std::endl;
return 0;
}

Returning the active member of a union using a function within it

or within its outer struct/class if anonymously nested. (<- to add to the title without making it longer).
I want to be able to simply call a function and get the member of a union being used (by any means, e.g returning it, modifying a parameter etc...), not the type (or an identifier for the type) but the actual member , or a non-void pointer to it. Is there a way to do this in modern (c++14) c++?
With boost::variant, the current value/type is stored. You may apply a static_visitor to the variant as for example:
#include "boost/variant.hpp"
#include <iostream>
class times_two_visitor : public boost::static_visitor<>
{
public:
void operator()(int & i) const
{
i *= 2;
}
void operator()(std::string & str) const
{
str += str;
}
};
int main()
{
boost::variant<int, std::string> u("hello world");
std::cout << u; // output: hello world
boost::apply_visitor(times_two_visitor(), u);
std::cout << u; // output: hello worldhello world
u = 21;
boost::apply_visitor(times_two_visitor(), u);
std::cout << u; // output: 42
}