Reference related issue compiling with Visual Studio 2008 but not with g++ - c++

the following code compiles with Visual Studio 2008 but not with g++ on Mac OSX:
class A
{
public:
A CreateA()
{
A a;
return a;
}
};
class B
{
public:
void ComputeWithA
(
A &a // Here, removing the reference solves the problem
)
{
return;
}
};
int main ()
{
A a;
B b;
b.ComputeWithA(a); // Works
b.ComputeWithA(a.CreateA()); // Invalid arguments 'Candidates are: void ComputeWithA(A &)'
return 0;
}
Why this reference related issue? Any explanation would be greatly appreciated.
Best regards.

a.CreateA() gives you a R-Value (i.e. a temporary). ComputeWithA wants a reference, aka L-Value. The standard says that you can't convert R- into L-Values, so the MSVC is wrong here.
However, you can take a const reference since this case is explicitly allowed:
void ComputeWithA(A const &a) // add a const and everything works fine

The code isn't legal but VC is accepting it. Your function returns a temporary, which cannot be bound to a non-const reference (which your function takes as its argument).
Can you change your function to take its parameter by const reference?

If you can't change the signature of the method, there is a workaround
class A
{
public:
A& operator()()
{
return *this;
}
...
b.ComputeWithA(a.CreateA()());
I've used this once when implementing a logger, because the temporary object was used in more operations.

Related

How does boost::ref work?

Having read couples of explanations here on StackOverflow, I still don't have a clue to how it works and what it is for. The demos I saw all use boost::reference_wrapper<int> as the type, that is, they all wrap int, and they also all run prefix op++ to show how it affects the wrapped int in the function template. One expert said the ref wrapper will be cast into the wrapped object if op++ is called on the ref wrapper, but it seems that it's not how it works. Please see the following example that demonstrates what would happen if the wrapped object is not an int. You may want to compile it before reading the code, so as to save your precious time.
// Build int version: g++ thisFile.cpp -Wall
// Build CFoo version: g++ -std=c++11 thisFile.cpp -DDONT_USE_INT -Wall
#include <boost/ref.hpp>
#include <iostream>
using namespace boost;
using namespace std;
class CFoo
{
public:
CFoo(int val) : m_val(val) {}
CFoo& operator++(void) {
++m_val;
return *this;
}
private:
int m_val;
friend ostream & operator<<(ostream& ostrm, const CFoo& param);
};
template <typename T>
void a_func_tmpl(T param)
{
++param;
}
ostream & operator<<(ostream& ostrm, const CFoo& param)
{
ostrm << param.m_val;
return ostrm;
}
int main(int argc, char *argv[])
{
#if defined(DONT_USE_INT)
CFoo obj(0);
#else
int obj(0);
#endif
a_func_tmpl(obj);
cout << obj << endl;
a_func_tmpl(ref(obj));
cout << obj << endl;
return 0;
}
Below is the output of compiling.
$ g++ -std=c++11 thisFile.cpp -Wall
$ ./a.out
0
1
$ g++ -std=c++11 thisFile.cpp -DDONT_USE_INT -Wall
thisFile.cpp: In instantiation of ‘void a_func_tmpl(T) [with T = boost::reference_wrapper<CFoo>]’:
thisFile.cpp:40:22: required from here
thisFile.cpp:22:2: error: no match for ‘operator++’ (operand type is ‘boost::reference_wrapper<CFoo>’)
++param;
^
As you can see, it does work if the wrapped type is int, but a compile-time error happens if the type is not int even if the wrapped type offers op++. It would be highly appreciated (I've been stuck on this for 2 days T_T) if someone can explain what really happens when a method of wrapped type is called on the wrapped ref. Thanks in advance. m(_ _)m
reference_wrapper is really simple, the easiest way to understand how it works is simply to look at the code. The generator functions, ref and cref that create a reference_wrapper are even simpler, again, just look at their definitions.
Understanding what it's for is also pretty simple: the intended use of reference_wrapper is to pass a variable by reference through a generic API that usually takes arguments by value. That's it.
That's useful when you have wrapped some function or functor in a forwarding API, and want to ensure the forwarding API passes references not values.
For instance, boost::bind copies its arguments into the callable object that it returns, and then invokes the target function passing the copied objects as arguments.
e.g. when you call boost::bind(&func, i) it returns a functor that contains a copy of &func and a copy of i. When you invoke that functor, it calls func with the copy of i. So if the function takes a reference, that reference is bound to the internal copy of i not to i itself. So if you have:
void func(int& i) { ++i; }
int i = 0;
auto bound = boost::bind(&func, i);
bound();
assert( i == 1 ); // FAILS!
The assertion will fail, because the int that gets passed to func is not i but a copy of i stored inside bound.
If you actually want the bound function to be called with a reference, you need something that is copyable like a value but implements reference semantics, which is where reference_wrapper comes in:
void func(int& i) { ++i; }
int i = 0;
auto bound = boost::bind(&func, boost::ref(i));
bound();
assert( i == 1 ); // passes
Now ref(i) creates a reference_wrapper<int> that refers to i and so bound contains a copy of that reference_wrapper<int>, also referring to i. When you invoke bound it passes the reference_wrapper<int> to func, which triggers the implicit conversion to int&, so that the reference binds to i, and i gets incremented as desired.
Other examples where you would use reference_wrapper are std::thread and std::async (and the Boost equivalents). They copy their arguments and then pass them to the wrapped target functor as rvalues, so if the functor has lvalue reference parameters then you must use reference_wrapper for the code to even compile.
Using reference_wrapper with your a_func_tmpl example doesn't really match the intended use, because the function doesn't take a reference, and you're not calling it through a generic API that would decay references to value anyway. Personally I wouldn't worry too much about why your example works in one case and not in the other, because it isn't the intended use case for reference_wrapper anyway. It's more important to understand what it is meant for, so you can use it in the appropriate places when necessary.
Your usage and understanding of reference_wrapper<> seems to actually be correct. However, you stumbled over another problem, which obscures that.
The problem is that there is no implicit conversion from reference_wrapper<CFoo> to CFoo& for the implicit this parameter. In this case, this would be needed to find operator++. However, it should work fine with a free-standing function that does the same:
void bar(CFoo& foo)
{
++foo;
}
template <typename T>
void a_func_tmpl(T param)
{
bar(param); // This allows the implicit conversion
}
Alternatively, you can implement operator++ as a free-standing function:
class CFoo
{
public:
CFoo (int val) : m_val (val) {}
private:
int m_val;
friend ostream & operator<<(ostream& ostrm, const CFoo& param);
friend CFoo& operator++(CFoo& foo);
};
CFoo& operator++(CFoo& foo) {
++foo.m_val;
return foo;
}
The only problem really is that the compiler doesn't know that it needs to convert from reference_wrapper<CFoo> to CFoo& to find operator++ if you define it in the class. The conversion is available, but it isn't asked for.
The code fails because ++param is calling boost::reference_wrapper<CFoo>::operator++ (because that's what you passed) for which there is no definition.
The interface of reference_wrapper<T> has a conversion operator to T&, but the compiler does not have a way to deduce that that's what you meant. x++ means 'call x::operator++', not 'find any old version of operator++ that I can coerce x into'
try
++(static_cast<T&>(param))
or
T& p = param;
++p;

Error passing shared_ptr<Derived>& as shared_ptr<Base>& without const

I got compile error when passing shared_ptr<Derived>& as shared_ptr<Base>&, see the below code and detailed question.
Note: this question is similar to "Passing shared_ptr<Derived> as shared_ptr<Base>" but not duplicate.
#include <memory>
class TBase
{
public:
virtual ~TBase() {}
};
class TDerived : public TBase
{
public:
virtual ~TDerived() {}
};
void FooRef(std::shared_ptr<TBase>& b)
{
// Do something
}
void FooConstRef(const std::shared_ptr<TBase>& b)
{
// Do something
}
void FooSharePtr(std::shared_ptr<TBase> b)
{
// Do something
}
int main()
{
std::shared_ptr<TDerived> d;
FooRef(d); // *1 Error: invalid initialization of reference of type ‘std::shared_ptr<TBase>&’ from expression of type ‘std::shared_ptr<TDerived>’
FooConstRef(d); // *2 OK, just pass by const reference
FooSharePtr(d); // *3 OK, construct a new shared_ptr<>
return 0;
}
Compiled by g++ -std=c++11 -o shared_ptr_pass_by_ref shared_ptr_pass_by_ref.cpp
Env: Ubuntu 14.04, g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2
Detailed question:
Why is it OK to pass by const reference (*2), but not OK to pass by reference (*1)?
Note: I know the best practice is to pass by const reference, but just want to know why the compile error occurs.
You seem to expect some kind of template covariance, whereby AnyTemplateClass<Derived> can bind to AnyTemplateClass<Base>&. Templates don't work this way. Generally, AnyTemplateClass<Derived> and AnyTemplateClass<Base> are two distinct, completely unrelated classes.
A specific template class may, or course, provide a relationship in some form. shared_ptr<T> in particular has a templated constructor accepting shared_ptr<U> for any U such that U* is convertible to T*.
FooConstRef(d) call works by constructing a temporary - effectively
shared_ptr<TBase> temp(d);
FooConstRef(temp);
But temporaries can't bind to non-const references, that's why FooRef(d) doesn't work in a similar way.

Accepting rvalue as lvalue reference [duplicate]

string foo() { return "hello"; }
int main()
{
//below should be illegal for binding a non-const (lvalue) reference to a rvalue
string& tem = foo();
//below should be the correct one as only const reference can be bind to rvalue(most important const)
const string& constTem = foo();
}
GCC is the good one to give a compile error: invalid initialization of non-const reference of type std::string& from a temporary of type std::string
VS2008 is not too bad as at least it gives a compile warning:
warning C4239: nonstandard extension used : 'initializing' :
conversion from std::string to std::string & A non-const
reference may only be bound to an lvalue
Here comes the problematic one - VS2010(SP1) comples fine WITHOUT any
error or warning, WHY ??!!
I know rvalue reference in VS2010 can be used to bind with rvalue but I am NOT using &&, instead in the demo code, I was just using non-const lvalue reference !
Can somone help me explain the behavior of VS2010 here? Is it a bug !?
Thanks
That is a known issue/feature of the VS compilers. They have always allowed that and there does not seem to be any push into removing that extension.
The compiler will issue an error with Disable Language Extensions turned on, and a warning at /W4. However, removing this code will break previously compiling code, and Microsoft is very reluctant to do that. This is also why they won't fix their SFINAE support.
Several years and many versions of Visual Studio later, we still have this "extension" causing surprises and headaches. Sigh...
The fix is to simply turn warning C4239 into an error. This will prevent MSVC from compiling code that attempts to bind a non-const lvalue reference to a temporary, and give you a nice clear compiler error. Simply add /we4239 to your compiler definitions or cl command line arguments.
In Visual Studio:
Project Properties > C/C++ > All Options > Treat Specific Warnings As Errors > add 4239, and make sure to separate any other numbers with a semicolon.
In CMake:
if(MSVC)
add_definitions("/we4239")
endif()
This seems to work far better than disabling all language extensions with /Za, which officially not recommend. On my large code base, adding /Za caused over 1500 compiler errors from Microsofts's own winnt.h header.
There is a much nastier variant of this problem:
class Foo {
int _val;
public:
Foo(int v) : _val(v) {}
void F() { std::cout << _val << std::endl; }
};
class Bar {
Foo& f;
public:
Bar(Foo& f) : f(f) {}
void F() { f.F(); }
};
int main() {
Bar b(Foo(3));
b.F();
}
So: to what does b.f point during the call to b.F()? The above example, compiled with VS2013 default Debug settings, runs without crashing and prints 3, but I'd suspect that any much more complex example will lead to stack corruption. If it doesn't and the compiler is doing something 'clever' to make it work, then I guess what it is really doing is this:
class Foo {
int _val;
public:
Foo(int v) : _val(v) {}
void F() { std::cout << _val << std::endl; }
};
class Bar {
Foo f;
public:
Bar(Foo&& f) : f(f) {}
void F() { f.F(); }
};
int main() {
Bar b(Foo(3));
b.F();
}

const references, constructors as parameter, and compilability

A colleague asked me to look over some code he was writing and came across a problem with a particular line, which the compiler (g++) would complain about a function call not having a matching function based on its parameters.
After solving the problem in two ways (one by moving the parameter to its own variable and passing that instead, next is changing the parameter list to take it as a const reference), I had to ask this question: Why is the solution the way it is? I wasn't satisfied with writing it off as if some constructor details were being hidden away, as my colleague puts it.
As a result, I've replicated and reduced the problem to the following (compile with g++ -Wall -ansi -pedantic):
class SomeClass
{
public:
static void SomeFunction(SomeClass& sc) {}
static void SomeFunction2(const SomeClass& sc) {}
};
class SomeChild : public SomeClass {};
void testOne(void)
{
// this compiles
SomeChild sc = SomeChild();
SomeClass::SomeFunction(sc);
// this doesn't compile
//SomeClass::SomeFunction(SomeChild());
}
void testTwo(void)
{
// this compiles
SomeChild sc = SomeChild();
SomeClass::SomeFunction2(sc);
// this compiles
SomeClass::SomeFunction2(SomeChild());
}
int main(void)
{
testOne();
testTwo();
return 0;
}
I'm probably missing something very fundamental here, but can anyone explain to me why the compiler thinks there is no matching function call for the uncompilable line?
Thanks in advance.
The simple reason is that temporary values, such as the value of SomeChild(), cannot bind to non-constant lvalue references. While there's no deep technical reason for this, it's a design choice: non-constant references are usually used to modify the thing that's being referred to, and if that thing is temporary, then the modification would essentially have no lasting effect, which is almost always logic error.
Just replace 'SomeFunction2' by 'SomeFunction':
#include <iostream>
class SomeClass
{
public:
static void SomeFunction(SomeClass& sc) { std::cout << "not const" << std::endl; }
static void SomeFunction(const SomeClass& sc) { std::cout << "const" << std::endl; }
};
class SomeChild : public SomeClass {};
int main(void)
{
SomeChild sc = SomeChild();
SomeClass::SomeFunction(sc);
SomeClass::SomeFunction(SomeChild());
return 0;
}
And all is good.
Without the change you bind a temporary to a reference, that is impossible. The only alternatives are 'T', 'const T&' or a universal reference 'T&&' ( http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers)

One VS2010 bug ? Allowing binding non-const reference to rvalue WITHOUT EVEN a warning?

string foo() { return "hello"; }
int main()
{
//below should be illegal for binding a non-const (lvalue) reference to a rvalue
string& tem = foo();
//below should be the correct one as only const reference can be bind to rvalue(most important const)
const string& constTem = foo();
}
GCC is the good one to give a compile error: invalid initialization of non-const reference of type std::string& from a temporary of type std::string
VS2008 is not too bad as at least it gives a compile warning:
warning C4239: nonstandard extension used : 'initializing' :
conversion from std::string to std::string & A non-const
reference may only be bound to an lvalue
Here comes the problematic one - VS2010(SP1) comples fine WITHOUT any
error or warning, WHY ??!!
I know rvalue reference in VS2010 can be used to bind with rvalue but I am NOT using &&, instead in the demo code, I was just using non-const lvalue reference !
Can somone help me explain the behavior of VS2010 here? Is it a bug !?
Thanks
That is a known issue/feature of the VS compilers. They have always allowed that and there does not seem to be any push into removing that extension.
The compiler will issue an error with Disable Language Extensions turned on, and a warning at /W4. However, removing this code will break previously compiling code, and Microsoft is very reluctant to do that. This is also why they won't fix their SFINAE support.
Several years and many versions of Visual Studio later, we still have this "extension" causing surprises and headaches. Sigh...
The fix is to simply turn warning C4239 into an error. This will prevent MSVC from compiling code that attempts to bind a non-const lvalue reference to a temporary, and give you a nice clear compiler error. Simply add /we4239 to your compiler definitions or cl command line arguments.
In Visual Studio:
Project Properties > C/C++ > All Options > Treat Specific Warnings As Errors > add 4239, and make sure to separate any other numbers with a semicolon.
In CMake:
if(MSVC)
add_definitions("/we4239")
endif()
This seems to work far better than disabling all language extensions with /Za, which officially not recommend. On my large code base, adding /Za caused over 1500 compiler errors from Microsofts's own winnt.h header.
There is a much nastier variant of this problem:
class Foo {
int _val;
public:
Foo(int v) : _val(v) {}
void F() { std::cout << _val << std::endl; }
};
class Bar {
Foo& f;
public:
Bar(Foo& f) : f(f) {}
void F() { f.F(); }
};
int main() {
Bar b(Foo(3));
b.F();
}
So: to what does b.f point during the call to b.F()? The above example, compiled with VS2013 default Debug settings, runs without crashing and prints 3, but I'd suspect that any much more complex example will lead to stack corruption. If it doesn't and the compiler is doing something 'clever' to make it work, then I guess what it is really doing is this:
class Foo {
int _val;
public:
Foo(int v) : _val(v) {}
void F() { std::cout << _val << std::endl; }
};
class Bar {
Foo f;
public:
Bar(Foo&& f) : f(f) {}
void F() { f.F(); }
};
int main() {
Bar b(Foo(3));
b.F();
}