Using auto with initializer list - c++

I have question regarding interaction between auto and initializer list. Example code:
#include <iostream>
int main()
{
auto a{ 1 };
auto b = { 1 };
auto c = 1;
std::cout << typeid(a).name() << std::endl;
std::cout << typeid(b).name() << std::endl;
std::cout << typeid(c).name() << std::endl;
return 0;
}
Gives output:
int
class std::initializer_list<int>
int
Which is kind of confusing. I'm posting this question as a followup to this. What should happen? I've did some research and it seems that auto c = 1; is illegal now, and it seems that it works because compilers allow this as a backwards compatibility patch. Does this apply also to auto a{1}?

Related

When using variant but error-invoke, could errors happens in compiling time instead of bad_variant_access in running time

If I have a map like
const std::map<int, std::variant<int, std::string>> m ={{1,1},{2,"asd"}};
But if i invoke std::get<string>(m[1]) by mistake instead of std::get<int>(m[1]), it will raise bad_variant_access.
But it is just a typo of codes, so could it be detected by IDE, or some form of static_assert could work because m is a constant(or what if m is not a constant) , or raise only compile errors?
If it is always constant, you don't need a map. You can dispatch that at compile time:
#include <iostream>
template <int i>
constexpr auto m()
{
if constexpr (i == 1) {
return 1;
} else if constexpr (i == 2) {
return "hello";
}
}
int main()
{
std::cout << m<1>() << '\n';
std::cout << m<2>() << '\n';
}
Or, just use a tuple:
#include <iostream>
#include <tuple>
int main()
{
std::tuple tuple { 1, "hello world" };
std::cout << std::get<0>(tuple) << '\n';
std::cout << std::get<1>(tuple) << '\n';
}

How can a simple std::cout << "---" << std::endl; alter how UB manifests?

Some background
Today I saw, in the body of a function kaboom, a local shared_ptr pointing to a *global object and, being captured by reference and its pointee returned by reference by a lambda, i.e. [&local]() -> auto& { return *local; }; this lambda was stored somehow for further use after the function kaboom returned.
As soon as I saw this, I thought the code was invoking undefined behavior. I tried to make a minimal example to support my claim, and came up with the following.
#include <iostream>
#include <memory>
#include <functional>
#include <vector>
struct Resource {
const int i{3};
};
std::shared_ptr<Resource> global = std::make_unique<Resource>();
auto getSharedStuff() {
return global;
}
std::vector<std::function<Resource&()>> actions{};
void kaboom() {
std::shared_ptr<Resource> local = getSharedStuff();
actions.push_back([&local]() -> auto& { return *local; });
}
int main() {
kaboom();
std::cout << global->i << std::endl;
std::cout << actions[0]().i << std::endl;
}
The simple fact that the 2 couts give 3 and 0 respectively is proof for me that I'm observing UB (3 is correct, and 0 could have been anything, including 3, but I've been lucky that it was not 3, so the UB is well manifest).
Good.
The code I'm curious about
But before getting there, an intermediate version of the repro above was this:
#include <iostream>
#include <memory>
#include <functional>
#include <vector>
struct Resource {
Resource(Resource const&) = delete;
Resource(Resource&&) = delete;
Resource() { std::cout << this << "'s ctor" << std::endl; }
~Resource() { std::cout << this << "'s dtor" << std::endl; }
void operator()() { std::cout << this << "'s operator()" << std::endl; }
};
std::shared_ptr<Resource> global = std::make_unique<Resource>();
auto getSharedStuff() {
return global;
}
std::vector<std::function<Resource&()>> actions{};
void kaboom() {
std::shared_ptr<Resource> local = getSharedStuff();
actions.push_back([&local]() -> auto& { return *local; });
}
int main() {
kaboom();
std::cout << "---" << std::endl;
actions[0]()();
}
which can result in this output
0xc602b0's ctor
---
0x7f0f48f7f4a0's operator()
0xc602b0's dtor
I'm kind of ok with this, as actions[0]()() is dereferencing a destroyed shared_ptr and calling operator() on the screwed up result, so I accept that this can be screwup too.
What's funny, though, is that removing std::cout << "---" << std::endl; makes UB less manifest, as the output becomes something like this:
0xce92b0's ctor
0xce92b0's operator()
0xce92b0's dtor
So my question is: how can a "simple" line as std::cout << "---" << std::endl; affect this way the manifestation of UB?

Integer pointer only has correct value if I print it

I am implementing my own smart_pointer, which counts the references to the thing it points to. Here is my implementation so far:
#pragma once
#include <iostream>
template <typename T>
class smart_pointer{
T* pointer;
int* cnt;
public:
smart_pointer<T>(T *el): pointer(el) { int i = 1; cnt = &i; }; //
smart_pointer<T>(const smart_pointer<T>& other): pointer(other.pointer) {
// std::cout << ", *(other.cnt): " << *(other.cnt);
cnt = other.cnt;
(*cnt)++;
} // Copy-constructor
int counter(){
int c = *cnt;
return c;
}
};
In main.cpp, I did the following:
int main(){
// smart_pointer_examples();
std::string h("hello");
smart_pointer<std::string> p(&h);
std::cout << "p: " << p.counter();
smart_pointer<std::string> q(p);
std::cout << ", q: " << q.counter() << std::endl;
return 0;
}
The problem is that that outputs p: 1, q: 6487781. After a lot of time trying to find the issue by debugging and printing stuff, I found something that fixed my issue: By adding std::cout << ", *(other.cnt): " << *(other.cnt); somewhere in my copy-constructor, the output becomes p: 1, *(other.cnt): 1, q: 2, which is the desired behaviour. I can't for the life of me think of why printing the counter would change anything.
Edit: Also, if I only do *(other.cnt) without std::cout, the same problem that I started with happens.
You made a small mistake in implementing your idea.
I will not comment on the design of your smart pointer implementation.
The problem is that you implemented your counter as a pointer. That is wrong.
And, you are dereferencing a local variable. That is a semantic bug. The result is undefined. The value of the counter will be indeterminate. Additionally you should initialize your class members.
If we fix both, then your code will look like:
#pragma once
#include <iostream>
template <typename T>
class smart_pointer {
T* pointer{};
int cnt{};
public:
smart_pointer<T>(T* el) : pointer(el) { cnt = 1; }; //
smart_pointer<T>(const smart_pointer<T>& other) : pointer(other.pointer) {
// std::cout << ", *(other.cnt): " << *(other.cnt);
cnt = other.cnt;
cnt++;
} // Copy-constructor
int counter() const {
return cnt;
}
};
int main() {
// smart_pointer_examples();
std::string h("hello");
smart_pointer<std::string> p(&h);
std::cout << "p: " << p.counter();
smart_pointer<std::string> q(p);
std::cout << ", q: " << q.counter() << std::endl;
return 0;
}

Is there a way to store multiple types of struct members pointers

I have this code who's working just fine to retrieve the foo members by index.
#include <string>
#include <iostream>
struct Foo {
int a = 42;
int b = 16;
std::string str = "hi";
};
int main()
{
int Foo::*members[] = { &Foo::a, &Foo::b };
Foo foo;
std::cout << foo.*members[1] << std::endl;
return 0;
}
The problem is that I have an std::string on my struct that I want to be able to access the same way, is there a solution scalable to any type?
What I've tried:
#include <string>
#include <iostream>
#include <any>
struct Foo {
int a = 42;
int b = 16;
std::string str = "coucou";
};
int main()
{
std::any Foo::*members[] = { (std::any Foo::*)&Foo::a, (std::any Foo::*)&Foo::b, (std::any Foo::*)&Foo::str };
Foo foo;
std::cout << std::any_cast<int>(foo.*members[0]) << std::endl;
return 0;
}
I told myself that if store an array of std::any, that will work. In fact, this code does compile but crashes.
Any solutions?
You might use std::tuple:
std::tuple members{&Foo::a, &Foo::b, &Foo::str }; // C++17 CTAD
// else, use `std::make_tuple`
Foo foo;
std::cout << foo.*std::get<0>(members) << " " << foo.*std::get<2>(members) << std::endl;
Demo
(I'll first say I agree with #MarekR's comment, that your question is likely an "XY problem" and you probably don't actually want to do this at all... but still:)
This is an interesting challenge - and one which has been tackled by the "crazy genius" Antony Polukhin, in his magic_get library - providing you are using the C++14 language standard, or later.
There is actually no need to store anything! The struct definition itself has all the information you need. Thus, when you write:
#include <iostream>
#include <string>
#include "boost/pfr.hpp" // <- Not formally a part of Boost, yet...
// you'll need to download the library from github
struct Foo {
int a = 42;
int b = 16;
std::string str = "hi";
};
int main() {
Foo my_foo;
std::cout
<< "a is " << boost::pfr::get<0>(my_foo) << ", "
<< "b is " << boost::pfr::get<1>(my_foo) << ", "
<< "and str is \"" << boost::pfr::get<2>(my_foo) << "\".\n";
}
you get:
a is 42, b is 16, and str is "hi".
just like you wanted.
To understand what the hell is going on, and where this black magic comes from, watch Antony's 2018 talk:
Better C++14 reflections - Antony Polukhin - Meeting C++ 2018
Try not to use a string as a pointer inside the Struct because it will not be pointing to nothing. Instead you can simply use like this:
std::cout << foo.str << std::endl;
It will output your string as well.

How to prevent compilation of passed lambda, if arguments are not references

In one of my projects I'm using a small utility function, which takes a Message struct and a lambda function, that modifies this message struct.
Now, I unintentionally passed a lambda without the necessary reference &. It perfectly compiles, but doesn't gave the desired output.
As for me, there should be one of the two following behaviors:
Forgetting to write auto&, but just auto should lead to compilation errors
Writing just auto should be interpreted as auto&.
It is possible to prevent compilation in case of a missing & or even better to interpret auto as auto& automatically?
#include <iostream>
#include <functional>
#include <boost/variant.hpp>
struct Message {
int x;
int y;
};
void changeMessage(Message& m, const std::function<void(Message&)>& messageModifier) {
std::cout << "Message before:" << m.x << " " << m.y << "\n";
messageModifier(m);
std::cout << "Message after:" << m.x << " " << m.y << "\n";
}
int main(int, char**) {
{
std::function<void(int&)> f = [](int&) {};
std::function<void(int)> g = [](int) {};
f = g; // This compiles.
}
{
std::function<void(int&)> f = [](int&) {};
std::function<void(int)> g = [](int) {};
//g = f; // This does not compile. Makes perfect sense.
}
Message m{ 10,20 };
{
changeMessage(m, [](auto m) { m.x++; m.y--; }); // User unintentionally forgot &! Can I prevent this from compilation?
std::cout << "Message outside: " << m.x << " " << m.y << "\n";
}
{
changeMessage(m, [](auto& m) { m.x++; m.y--; });
std::cout << "Message outside: " << m.x << " " << m.y << "\n";
}
}
One way to prevent passing Message by value (and auto itself is never a reference) is to disable copy construction:
struct Message {
Message() = default;
Message(const Message&) = delete;
int x;
int y;
};
Another solution suggested by #L. F. is to check that lambda doesn't accept rvalues:
template<class Fn>
void change_message(Message& m, Fn fn) {
static_assert(!std::is_invocable_v<Fn, Message&&>);
fn(m);
}