Minimal working example:
#include <tuple>
struct example
{
example(int, char) {}
};
int main()
{
std::tuple<example, int, double>
my_tuple(example(0, 'x'), 42, .0);
// std::tuple t = make_my_tuple(0, 'x');
return 0;
}
This works.
Is there a more elegant way to initialize only the first member, like I sketched in the comment? One which only takes the arguments to construct the first tuple member and does not initialize the others?
The reason I ask? I am just interested in the semantics of the language.
You say that giving values for the other two members is not necessary - are you worried about performance? Or that there may be no suitable value for these members?
If it's the latter, you could have your tuple hold boost::optionals. e.g.
#include <tuple>
#include <boost/optional.hpp>
using namespace boost;
struct example
{
example(int, char) {}
};
typedef std::tuple<example, optional<int>, optional<double>> MyTuple;
int main()
{
MyTuple my_tuple(example(0, 'x'), optional<int>(), optional<double>());
return 0;
}
You now semantically have the int and float "uninitialised", and can query their value as such.
To make this more elegant, you can wrap this into a function, using the perfect forwarding idiom for the arguments (in general; in this case your arguments are cheap to copy, so no speed benefit from doing this):
template <class... Args>
MyTuple make_mytuple(Args&&... args)
{
return MyTuple(example(std::forward<Args>(args)...), optional<int>(), optional<double));
}
The advantage of this template is that it's resilient to changes in example's constructor. If you add another argument, just call make_mytuple with the new arguments and it will work.
Your other point about the copying in the tuple construction is valid, but in reality I believe this will be optimal on most compilers. (a combination of RVO and elision of copies when passing an rvalue to a function by value).
You can use uniform initialization. Sadly, you cannot define a default value, argument will be initialized with the default constructor or 0.
#include <iostream>
#include <tuple>
enum class Result {Full, Partial, Empty};
std::tuple<bool, int, double> get_tuple(Result type)
{
if (type == Result::Full)
return {true, 42, 3.14159};
else if (type == Result::Partial)
return {true, 42, {}};
else
return {};
}
int main()
{
bool b;
int i;
double d;
std::tie(b, i, d) = get_tuple(Result::Full);
std::cout << b << " " << i << " " << d << std::endl;
std::tie(b, i, d) = get_tuple(Result::Partial);
std::cout << b << " " << i << " " << d << std::endl;
std::tie(b, i, d) = get_tuple(Result::Empty);
std::cout << b << " " << i << " " << d << std::endl;
return 0;
}
output:
1 42 3.14159
1 42 0
0 0 0
Related
I am trying to create a map with string as key and a generic method as value in C++, but I do not know if that is even possible. I would like to do something like that:
void foo(int x, int y)
{
//do something
}
void bar(std::string x, int y, int z)
{
//do something
}
void main()
{
std::map<std::string, "Any Method"> map;
map["foo"] = &foo; //store the methods in the map
map["bar"] = &bar;
map["foo"](1, 2); //call them with parameters I get at runtime
map["bar"]("Hello", 1, 2);
}
Is that possible? If yes, how can I realise this?
You can type-erase the function types into a container, then provide a template operator(). This will throw std::bad_any_cast if you get it wrong.
N.B. because of the type erasure, you will have to specify exactly matching arguments at the call site, as e.g. std::function<void(std::string)> is distinct from std::function<void(const char *)>, even though both can be called with a value like "Hello".
#include <any>
#include <functional>
#include <map>
#include <string>
#include <iostream>
template<typename Ret>
struct AnyCallable
{
AnyCallable() {}
template<typename F>
AnyCallable(F&& fun) : AnyCallable(std::function(std::forward<F>(fun))) {}
template<typename ... Args>
AnyCallable(std::function<Ret(Args...)> fun) : m_any(fun) {}
template<typename ... Args>
Ret operator()(Args&& ... args)
{
return std::invoke(std::any_cast<std::function<Ret(Args...)>>(m_any), std::forward<Args>(args)...);
}
std::any m_any;
};
void foo(int x, int y)
{
std::cout << "foo" << x << y << std::endl;
}
void bar(std::string x, int y, int z)
{
std::cout << "bar" << x << y << z << std::endl;
}
using namespace std::literals;
int main()
{
std::map<std::string, AnyCallable<void>> map;
map["foo"] = &foo; //store the methods in the map
map["bar"] = &bar;
map["foo"](1, 2); //call them with parameters I get at runtime
map["bar"]("Hello, std::string literal"s, 1, 2);
try {
map["bar"]("Hello, const char *literal", 1, 2); // bad_any_cast
} catch (std::bad_any_cast&) {
std::cout << "mismatched argument types" << std::endl;
}
map["bar"].operator()<std::string, int, int>("Hello, const char *literal", 1, 2); // explicit template parameters
return 0;
}
The most (I cannot say best here) you can do is to use a signature erasure. That mean to convert the pointer to functions to a common signature type, and then convert them back to the correct signature before using them.
That can only be done in very special use cases (I cannot imagine a real world one) and will be highly unsecure: nothing prevent you to pass the wrong parameters to a function. In short: NEVER DO THIS IN REAL WORLD CODE.
That being said, here is a working example:
#include <iostream>
#include <string>
#include <map>
typedef void (*voidfunc)();
void foo(int x, int y)
{
std::cout << "foo " << x << " " << y << std::endl;
}
void bar(std::string x, int y, int z)
{
std::cout << "bar " << x << " " << y << " " << z << std::endl;
}
int main()
{
std::map<std::string, voidfunc> m;
m["foo"] = (voidfunc) &foo;
m["bar"] = (voidfunc)& bar;
((void(*)(int, int)) m["foo"])(1, 2);
((void(*)(std::string, int, int)) m["bar"])("baz", 1, 2);
return 0;
}
It gives as expected:
foo 1 2
bar baz 1 2
I could not find in standard whether this invokes or not Undefined Behaviour because little is said about function pointer conversions, but I am pretty sure that all common compilers accept that, because it only involve function pointers casting.
You cannot store functions with different signatures in a container like map, no matter if you store them as a function pointer or std ::function<WHATEVER>. The information about the signature of the function is one and only one in both cases.
The types for the value in map is one, meaning that the object stored in it are all of the same type.
So if your functions have all the same signature, then it's easy, otherwise, you have to abandon type safety and start walking in a very dangerous realm.
The one in which you erase the type information about the functions stored inside the map.
This translates to something like map<string, void*>.
I know that I shouldn't overload a function for just parameters differ only in one of them passed by copy and the other by reference:
void foo(int x)
{
cout << "in foo(int x) x: " << x << endl;
}
void foo(int& x)
{
cout << "in foo(int& x) x: " << x << endl;
}
int main()
{
int a = 1;
foo(5); // ok as long as there is one best match foo(int)
foo(a); // error: two best candidates so the call is ambiguous
//foo(std::move(a));
//foo(std::ref(an)); // why also this doesn't work?
}
So a code that uses std::bind can be like this:
std::ostream& printVec(std::ostream& out, const std::vector<int> v)
{
for (auto i : v)
out << i << ", ";
return out;
}
int main()
{
//auto func = std::bind(std::cout, std::placeholders::_1); // error: stream objects cannot be passed by value
auto func = std::bind(std::ref(std::cout), std::placeholders::_1); // ok.
}
So std::ref here to ensure passing by reference rather than by value to avoid ambiguity?
* The thing that matters me: Does std::bind() implemented some wrapper to overcome this issue?
Why I can't use std::ref in my example to help the compiler in function matching?
Now that you know passing by value and reference are ambiguous when overload resolution tries to compare them for choosing a best viable function, let's answer how would you use std::ref (or std::cref) to differentiate between pass-by-value and pass-by-reference.
It turns out to be ... pretty simple. Just write the overloads such that one accepts a int, and the other accepts a std::reference_wrapper<int>:
#include <functional>
#include <iostream>
void foo(int x) {
std::cout << "Passed by value.\n";
}
void foo(std::reference_wrapper<int> x) {
std::cout << "Passed by reference.\n";
int& ref_x = x;
ref_x = 42;
/* Do whatever you want with ref_x. */
}
int main() {
int x = 0;
foo(x);
foo(std::ref(x));
std::cout << x << "\n";
return 0;
}
Output:
Passed by value.
Passed by reference.
42
The function pass the argument by value by default. If you want to pass by reference, use std::ref explicitly.
Now let's answer your second question: how does std::bind deal with this type of scenario. Here is a simple demo I have created:
#include <functional>
#include <type_traits>
#include <iostream>
template <typename T>
struct Storage {
T data;
};
template <typename T>
struct unwrap_reference {
using type = T;
};
template <typename T>
struct unwrap_reference<std::reference_wrapper<T>> {
using type = std::add_lvalue_reference_t<T>;
};
template <typename T>
using transform_to_storage_type = Storage<typename unwrap_reference<std::decay_t<T>>::type>;
template <typename T>
auto make_storage(T&& obj) -> transform_to_storage_type<T> {
return transform_to_storage_type<T> { std::forward<T>(obj) };
}
int main() {
int a = 0, b = 0, c = 0;
auto storage_a = make_storage(a);
auto storage_b = make_storage(std::ref(b));
auto storage_c = make_storage(std::cref(c));
storage_a.data = 42;
storage_b.data = 42;
// storage_c.data = 42; // Compile error: Cannot modify const.
// 0 42 0
std::cout << a << " " << b << " " << c << "\n";
return 0;
}
It is not std::bind, but the method used is similar (it's also similar to std::make_tuple, which has the same semantic). make_storage by default copies the parameter, unless you explicitly use std::ref.
As you can see, std::ref is not magic. You need to do something extra for it to work, which in our case is to first decay the type (all references are removed in this process), and then check whether the final type is a reference_wrapper or not; if it is, unwrap it.
I am trying to create a map with string as key and a generic method as value in C++, but I do not know if that is even possible. I would like to do something like that:
void foo(int x, int y)
{
//do something
}
void bar(std::string x, int y, int z)
{
//do something
}
void main()
{
std::map<std::string, "Any Method"> map;
map["foo"] = &foo; //store the methods in the map
map["bar"] = &bar;
map["foo"](1, 2); //call them with parameters I get at runtime
map["bar"]("Hello", 1, 2);
}
Is that possible? If yes, how can I realise this?
You can type-erase the function types into a container, then provide a template operator(). This will throw std::bad_any_cast if you get it wrong.
N.B. because of the type erasure, you will have to specify exactly matching arguments at the call site, as e.g. std::function<void(std::string)> is distinct from std::function<void(const char *)>, even though both can be called with a value like "Hello".
#include <any>
#include <functional>
#include <map>
#include <string>
#include <iostream>
template<typename Ret>
struct AnyCallable
{
AnyCallable() {}
template<typename F>
AnyCallable(F&& fun) : AnyCallable(std::function(std::forward<F>(fun))) {}
template<typename ... Args>
AnyCallable(std::function<Ret(Args...)> fun) : m_any(fun) {}
template<typename ... Args>
Ret operator()(Args&& ... args)
{
return std::invoke(std::any_cast<std::function<Ret(Args...)>>(m_any), std::forward<Args>(args)...);
}
std::any m_any;
};
void foo(int x, int y)
{
std::cout << "foo" << x << y << std::endl;
}
void bar(std::string x, int y, int z)
{
std::cout << "bar" << x << y << z << std::endl;
}
using namespace std::literals;
int main()
{
std::map<std::string, AnyCallable<void>> map;
map["foo"] = &foo; //store the methods in the map
map["bar"] = &bar;
map["foo"](1, 2); //call them with parameters I get at runtime
map["bar"]("Hello, std::string literal"s, 1, 2);
try {
map["bar"]("Hello, const char *literal", 1, 2); // bad_any_cast
} catch (std::bad_any_cast&) {
std::cout << "mismatched argument types" << std::endl;
}
map["bar"].operator()<std::string, int, int>("Hello, const char *literal", 1, 2); // explicit template parameters
return 0;
}
The most (I cannot say best here) you can do is to use a signature erasure. That mean to convert the pointer to functions to a common signature type, and then convert them back to the correct signature before using them.
That can only be done in very special use cases (I cannot imagine a real world one) and will be highly unsecure: nothing prevent you to pass the wrong parameters to a function. In short: NEVER DO THIS IN REAL WORLD CODE.
That being said, here is a working example:
#include <iostream>
#include <string>
#include <map>
typedef void (*voidfunc)();
void foo(int x, int y)
{
std::cout << "foo " << x << " " << y << std::endl;
}
void bar(std::string x, int y, int z)
{
std::cout << "bar " << x << " " << y << " " << z << std::endl;
}
int main()
{
std::map<std::string, voidfunc> m;
m["foo"] = (voidfunc) &foo;
m["bar"] = (voidfunc)& bar;
((void(*)(int, int)) m["foo"])(1, 2);
((void(*)(std::string, int, int)) m["bar"])("baz", 1, 2);
return 0;
}
It gives as expected:
foo 1 2
bar baz 1 2
I could not find in standard whether this invokes or not Undefined Behaviour because little is said about function pointer conversions, but I am pretty sure that all common compilers accept that, because it only involve function pointers casting.
You cannot store functions with different signatures in a container like map, no matter if you store them as a function pointer or std ::function<WHATEVER>. The information about the signature of the function is one and only one in both cases.
The types for the value in map is one, meaning that the object stored in it are all of the same type.
So if your functions have all the same signature, then it's easy, otherwise, you have to abandon type safety and start walking in a very dangerous realm.
The one in which you erase the type information about the functions stored inside the map.
This translates to something like map<string, void*>.
Sample:
#include "stdafx.h"
#include <functional>
#include <iostream>
#include <string>
std::function<void(int)> Foo()
{
int v = 1;
int r = 2;
auto l = [v, r](int i)
{
std::cout << v << " " << r << " " << i << std::endl;
};
return l;
}
int main()
{
auto func = Foo();
func(3);
return 0;
}
Why func(3) can pass 3 to i which is the formal argument of the lambda in Foo(). I can't think out. thanks.
TL;DR: You don't pass your argument 3 into a function Foo. You pass it to a method of an object func.
A bit more detailed explanation is below.
First of all, I would like to clarify what a lambda is. A lambda in C++ is nothing more than an anonymous functor class, so essentially just a syntactic sugar. A closure is an instance of a lambda type. However, quite often you can hear words "lambda" and "closure" being used interchangeably.
So within your function Foo() you create a closure object l
auto l = [v, r](int i)
{
std::cout << v << " " << r << " " << i << std::endl;
};
which would be technically equivalent to this code:
struct Functor
{
Functor(int v, int r) : v_(v), r_(r) {}
void operator ()(int i) const {
std::cout << v_ << " " << r_ << " " << i << std::endl;
}
private:
int v_;
int r_;
};
Functor l(v, r);
Now, on the next line you return an std::function object.
return l; // actually creates std::function<void(int)>(l) and returns it
So in your main function a func is just an object which stores copies of values v, r obtained during a call to Foo() and defines operator(), similar to the struct above.
Therefore, calling func(3) you actually invoke an object method on a concrete object func, and without syntactic sugar it looks like func.operator()(3).
Here's a live example to illustrate my point.
Hope that helps to resolve your confusion.
I have read many posts about variadic templates and std::bind but I think I am still not understanding how they work together. I think my concepts are a little hazy when it comes to using variadic templates, what std::bind is used for and how they all tie together.
In the following code my lambda uses the dot operator with objects of type TestClass but even when I pass in objects of type std::ref they still work. How is this exactly? How does the implicit conversion happen?
#include <iostream>
using std::cout;
using std::endl;
#include <functional>
#include <utility>
using std::forward;
class TestClass {
public:
TestClass(const TestClass& other) {
this->integer = other.integer;
cout << "Copy constructed" << endl;
}
TestClass() : integer(0) {
cout << "Default constructed" << endl;
}
TestClass(TestClass&& other) {
cout << "Move constructed" << endl;
this->integer = other.integer;
}
int integer;
};
template <typename FunctionType, typename ...Args>
void my_function(FunctionType function, Args&&... args) {
cout << "in function" << endl;
auto bound_function = std::bind(function, args...);
bound_function();
}
int main() {
auto my_lambda = [](const auto& one, const auto& two) {
cout << one.integer << two.integer << endl;
};
TestClass test1;
TestClass test2;
my_function(my_lambda, std::ref(test1), std::ref(test2));
return 0;
}
More specifically, I pass in two instances of a reference_wrapper with the two TestClass objects test1 and test2, but when I pass them to the lambda the . operator works magically. I would expect that you have use the ::get() function in the reference_wrapper to make this work but the call to the .integer data member works..
The reference unwrapping is performed by the result of std::bind():
If the argument is of type std::reference_wrapper<T> (for example, std::ref or std::cref was used in the initial call to bind), then the reference T& stored in the bound argument is passed to the invocable object.
Corresponding standardese can be found in N4140 draft, [func.bind.bind]/10.
It is important to note that with std::bind;
The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or std::cref.
The "passed by reference" above is achieved because std::ref provides a result of std::reference_wrapper that is a value type that "wraps" the reference provided.
std::reference_wrapper is a class template that wraps a reference in a copyable, assignable object. It is frequently used as a mechanism to store references inside standard containers (like std::vector) which cannot normally hold references.
By way of an example of what bind's unwrapping of the reference does (without the bind);
#include <iostream>
#include <utility>
#include <functional>
int main()
{
using namespace std;
int a = 1;
auto b = std::ref(a);
int& c = b;
cout << a << " " << b << " " << c << " " << endl; // prints 1 1 1
c = 2;
cout << a << " " << b << " " << c << " " << endl; // prints 2 2 2
}
Demo code.