I'm puzzled about the boost::make_optional() behavior when used with the template specification.
In particular, it's still unclear to me why this:
int pizza = 5;
boost::optional<int> pizza_opt = boost::make_optional<int>(pizza)
throws the compile error cannot bind rvalue reference of type ‘int&&’ to lvalue of type ‘int’; while this:
int foo(int bar)
{ return bar; }
boost::optional<int> pizza_opt = boost::make_optional<int>(foo(pizza))
works fine.
I already know from this that it does not make much sense to use boost::make_optional specifying the type, but I'm reading some code which does use of this structure.
Thank you!
Template parameter of boost::make_optional doesn't define exactly type inside optional.
This template parameter is responsible for perfect forwarding, here is simple minimal example reproducing issue:
#include <iostream>
template<typename T>
void bar(T&& x)
{
std::cout << __PRETTY_FUNCTION__ << " "
<< std::forward<T>(x) << '\n';
}
int foo(int x)
{
return x + 1;
}
int main()
{
int pizza = 5;
bar(pizza);
bar<int>(foo(pizza));
// bar<int>(pizza); // same error
return 0;
}
Live demo.
So when deduction is done T is int& for l-values and int for r-values.
When you pass variable you passing l-value.
When you specified type you are forcing argument to be int && which do not match to int&.
Related
If we have this example functions code in C++
void foo(int x) { std::cout << "foo(int)" << std::endl; }
void foo(int& x) { std::cout << "foo(int &)" << std::endl; }
Is it possible to difference what function to call doing any modification in the calling arguments?
If the function foo is called in some of these ways:
foo( 10);
i = 10;
foo( static_cast<const int>(i));
foo( static_cast<const int&>(i));
it's called the first foo overloaded function, because it can't pass by reference a const argument to a non-const parameter.
But, how would you do to call the second foo overload function?
If I call the next way:
int i = 10;
foo( i);
It happens an ambiguous error because both functions are valid for this argument.
In this link https://stackoverflow.com/a/5465379/6717386 it's explained one way to resolve it: using objects instead of built-in types and doing private the copy constructor, so it can't do a copy of object value and it has to be called the second foo overload function and passing the object by reference. But, is there any way with the built-in types? I have to change the name of function to avoid the overloading?
You may do a cast (of the function) to select the overload function:
static_cast<void (&)(int&)>(foo)(i);
Demo
In most instance, function overloading involves distinct parameter types and different input parameter lengths.
Your attempt is generally a bad practice and the resulting compiled code is compiler dependent and code optimization may even worsen things even more.
You may consider simply adding a second parameter to the second method, something like this:
void foo(int x) { std::cout << "foo(int)" << std::endl; }
void foo(int& x, ...) { std::cout << "foo(int &, ...)" << std::endl; }
where ... could be a boolean type, say: bool anotherFunction
So calling foo(param1, param2) would simply call the second code and everybody is fine.
Very strange design, but if you want... I'll offer a solution as strange as your design Use Xreference in function signature. Then in the function you can check what you need to do using std::is_lvalue_reference, std::is_rvalue_reference.
Something like this
template<class T>
void foo(T&& x)
{
static_assert(std::is_same<std::decay_t<T>, int>::value, "!");
if (std::is_rvalue_reference<T&&>::value)
std::cout << "do here what you want in foo(int x)";
else
std::cout << "do here what you want in foo(int & x)";
}
int main()
{
int x = 5;
foo(x); //"do here what you want in foo(int x)" - will be printed
foo(std::move(x)); //"do here what you want in foo(int & x)" - will be printed
}
Despite the good answer of #Jarod42, as an alternative solution you can rely on a templated entry point and the overloading of an internal function (if you don't want to deal with explicit casts, of course).
It follows a minimal, working example:
#include<type_traits>
#include<iostream>
#include<utility>
void foo_i(char, int x) { std::cout << "foo(int)" << std::endl; }
void foo_i(int, int &x) { std::cout << "foo(int &)" << std::endl; }
template<typename T>
void foo(T &&t) {
static_assert(std::is_same<std::decay_t<T>, int>::value, "!");
foo_i(0, std::forward<T>(t));
}
int main() {
foo( 10);
int i = 10;
foo( static_cast<const int>(i));
foo( static_cast<const int &>(i));
foo(i);
}
The static_assert serves the purpose of checking the parameter to be something that involves int (that is int, int &, const int &, int &&`, and so on).
As you can see from the code above, foo(i) will print:
foo(int &)
As expected.
Another one:
#include <iostream>
#include <functional>
void foo(int x)
{
std::cout << "foo(int)\n";
}
template<typename T>
void foo(T&& x)
{
std::cout << "foo(int&)\n";
}
int main()
{
int i = 10;
foo(i); // foo(int)
foo(std::ref(i)); // foo(int&)
}
I just happened to have stumbled upon this post and was surprised not to find the typical SFINAE solution. So, there you go:
#include <iostream>
#include <type_traits>
template<typename T,
typename std::enable_if<!std::is_lvalue_reference<T>{}, int>::type = 0>
void foo(T)
{ std::cout << "foo(int)" << std::endl; }
template<typename T,
typename std::enable_if<std::is_lvalue_reference<T>{}, int>::type = 0>
void foo(T&)
{ std::cout << "foo(int &)" << std::endl; }
int main() {
int i = 42;
int& r = i;
foo<decltype(i)>(i);
foo<decltype(r)>(r);
}
Live example
All try to do is to make this piece of code
int main() {
if constexpr( ??? ) {
std::cout << "Yes\n";
std::cout << f() << '\n';
std::cout << f(42) << '\n';
}
else {
std::cout << "No\n";
}
return 0;
}
compile if the function f is defined as in any of these examples
// Example 1
int f(int n = 0) { return n; }
// Example 2
int f(int n) { return n; }
int f() { return 0; }
// Example 3
int f(int n) { return n; }
and display Yes for examples 1 and 2, and display No for the example 3.
Is this even possible? I think I've seen someone doing this with SFINAE but I don't remember how exactly it was done and where exactly I saw that. Thank you in advance.
if constexpr can’t protect ill-formed code outside of any template (e.g., in main). The obvious thing to do is to write a template that accepts f itself as a template argument, but to do that you have to reify your overload set. The usual way to do that is as a SFINAE-friendly function object:
template<class F,class=void>
constexpr bool opt=false;
template<class F>
constexpr bool opt<F,decltype(std::declval<F>()(1),void(std::declval<F>()()))> =true;
template<class F> int use(F &&x) {
if constexpr(opt<F>) return x(1)+x();
else return 0;
}
const auto f_=[](auto &&...aa) -> decltype(f(std::forward<decltype(aa)>(aa)...))
{return f(std::forward<decltype(aa)>(aa)...);};
int main() {use(f_);}
In some cases there is also the option of creating a “fake” template that uses calls that are formally dependent but always use the types you want, but that’s impossible for a call f() with no arguments, which is ill-formed (possibly with no diagnostic required) immediately if your f requires an argument since it can’t depend on a template parameter.
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.
Here is my code:
struct S
{
int f() { return 1; }
int g(int arg = f()) { return arg; }
};
int main()
{
S s;
return s.g();
}
This fails to compile with the error:
error: cannot call member function 'int S::f()' without object
Trying this->f() doesn't work either, as this may not be used in that context.
Is there a way to make this work, still using the default argument?
Of course it can be worked around by not using default arguments at all:
int g(int arg) { return arg; }
int g() { return g(f()); }
however that gets verbose considering that in the "real code" there are more parameters before arg, and several functions following this pattern. (And even more ugly if there were multiple default arguments in the one function).
NB. This question looks similar at first, but in fact he is asking how to form a closure, which is a different problem (and the linked solution doesn't apply to my situation).
You can only use members there if they are static. From a C++11 draft standard (n3299), §8.3.6/9:
Similarly, a non-static member shall not be used in a default argument, even if it is not evaluated, unless it appears as the id-expression of a class member access expression (5.2.5) or unless it is
used to form a pointer to member (5.3.1).
E.g., this works:
struct S {
static int f() { return 1; }
int g(int arg = f()) { return arg; }
};
int main()
{
S s;
return s.g();
}
This also works (I think that's what the first expression means):
struct S {
int f() { return 42; }
int g(int arg);
};
static S global;
int S::g(int arg = global.f()) { return arg; }
int main()
{
S s;
return s.g();
}
As for this, it is indeed not allowed (§8.3.6/8):
The keyword this shall not be used in a default argument of a member function.
The default arguments page on cppreference.com has a lot of details regarding the subject—it can get quite complex.
If you are allowed to use experimental features from C++17, you can use std::optional from the STL (see here for further details).
In other terms something like:
int g(std::optional<int> oarg = std::optional<int>{}) {
int arg = oarg ? *oarg : f();
// go further
}
EDIT
As suggested in the comments, the code above should be logically equivalent to the one below:
int g(std::optional<int> oarg = std::optional<int>{}) {
int arg = oarg.value_or(f());
// go further
}
This one is a bit more readable (isn't it?), but please note that it executes f in any case.
If that function is expensive, maybe it doesn't worth it.
I add another answer, that is completely different from the previous one and could solve your issue.
The idea is to use another class and the right mix of explicit and non-explicit constructors.
It follows a minimal, working example:
#include <functional>
#include <iostream>
template<class C, int(C::*M)()>
struct Arg {
std::function<int(C*)> fn;
Arg(int i): fn{[i](C*){ return i; }} { }
explicit Arg(): fn{[](C* c){ return (c->*M)(); }} { }
};
struct S {
int f() { return 1; }
int h() { return 2; }
void g(int arg0,
Arg<S, &S::f> arg1 = Arg<S, &S::f>{},
Arg<S, &S::h> arg2 = Arg<S, &S::h>{})
{
std::cout << "arguments" << std::endl;
std::cout << "arg0: " << arg0 << std::endl;
std::cout << "arg1: " << arg1.fn(this) << std::endl;
std::cout << "arg2: " << arg2.fn(this) << std::endl;
}
};
int main() {
S s{};
s.g(42, 41, 40);
s.g(0);
}
The example shows how you can mix both default parameters and non defaulted ones.
It's quite simple to modify it and let g be a function having an empty argument list, as in the original question.
I'm also quite sure that one can refine the example and end with something better than that, anyway it should be a good point from which to start.
It follows the solution applied to the original example from the question:
#include <functional>
template<class C, int(C::*M)()>
struct Arg {
std::function<int(C*)> fn;
Arg(int i): fn{[i](C*){ return i; }} { }
explicit Arg(): fn{[](C* c){ return (c->*M)(); }} { }
};
struct S {
int f() { return 1; }
int g(Arg<S, &S::f> arg = Arg<S, &S::f>{}) {
return arg.fn(this);
}
};
int main() {
S s{};
return s.g();
}
And that's all, it's possible to do that, even without static methods or global variables.
Of course, we can use our this somehow. It's a matter of bending the language a bit...
Is there a way to remove the 'plumb' version of all of my functions, without the need to change the 'hit' line to the 'fixed'?
Yes my program works fine, but I think if is there a way to get ride from this version of all of my functions.
Keep in mind that int is not really int in my programs, but a type alias which can be object ( e.g. container_reference<std::array<double,4>> ) or reference ( e.g. std::array<double,4> & )
void func(int &&m) { cout << "rvalue: " << m << endl; }
void func(int &m) { cout << "lvalue: "; func(std::move(m)); } // PLUMB!
int main()
{
int a = 5;
func(a); // HIT!
func(std::move(a)); // FIXED!
func(6);
func(a + 5);
}
I'm having a bit of trouble understand exactly what you want, but this might be an option:
template<typename T>
void func(T &&m) {
// ...
}
T&& has been dubbed "universal reference" as it will bind to both lvalues and rvalues due to reference collapsing rules.