I have the following function
void AddNodeValue(XMLNode& node, std::string& value);
I want to use it like this:
document.AddNodeValue(modvalue,"modvalue");
and the compiler complains:
error C2664: 'void XML::XMLDocument::AddNodeValue(XML::XMLNode &,std::string &)' : cannot convert parameter 2 from 'const char [9]' to 'std::string &'
A reference that is not to 'const' cannot be bound to a non-lvalue
I don't get why that is wrong?
Compiler: VS2003
Your function needs to take const std::string& for you to use it like that.
C++ has a rule that an rvalue (in your case, a temporary std::string which is created from the string literal) can be bound with a const reference, but not a non-const reference.
As far as I know, this restriction isn't due to any fundamental implementation problem, since temporary values can be modified in other ways. But a function which takes a non-const reference is assumed to do so because its main purpose is to modify that argument. It doesn't usually make a lot of sense to do that with a temporary, so possibly banning it catches errors far more than it prevents people doing something worthwhile. Anyway, not all rvalues are temporaries: some are literals which really cannot be modified.
If you can't change the function AddNodeValue, then you can work around it:
std::string valstr("modvalue");
document.AddNodeValue(modvalue, valstr);
// valstr might have changed, check the documentation of AddNodeValue
Related
The following gives a compiler error:
#include <string>
const std::string& get_name();
int main(){
auto&& name1 = get_name();//should bind to whatever
const auto& name2 = get_name();//also ok
const auto&& name3 = get_name();//<-not ok, why ?
return 0;
}
Link to godbolt: https://godbolt.org/z/l6IQQ7
If I use const auto& it compiles - but that will not bind to value.
auto&& will be bind to anything so that naturally works as well.
However, what is the logic behind const auto&& not binding in this case ?
I know auto&& will preserve the constness - but is there a way to be const explicit and at the same time be reference/value agnostic ?
Motivation:
For 'normal programming work' inside functions etc. it would be great to be able to say something like: "I do not care if it's a value or reference - but I do not change it for the rest of the function".
This should be possible given current language.
Related question: Why adding `const` makes the universal reference as rvalue
For 'normal programming work' inside functions etc. it would be great
to be able to say something like: "I do not care if it's a value or
reference - but I do not change it for the rest of the function".
You already have the solution at hand for your motivation: use const auto&. const auto& will bind to:
const lvalue refs
lvalue refs
const rvalue refs
rvalue refs
Additionally, it will extend the lifetime of returned values
So you got everything you need. Yes, it is different from a const rvalue ref, but that wont matter if you just use it, since you wont be able to move from it anyway, since it is const.
Last note: auto&& will always be a reference. its a forwarding reference with deduction, but your final variable will ALWAYS be a reference (rvalue ref or lvalue ref, but never a "value"). Maybe that was/is a misconception?
I am just curious. I am passing pointer to function with signature
void printCommandReceived(const CommandDescriptor &descriptor)
as third parameter to constructor with signature
CommandLogFilter::CommandLogFilter(QSharedPointer<LogServer> logServer, QObject *parent,
void (*preprocessValidCommand)(CommandDescriptor &descriptor))
and getting error from g++ compiler:
error: invalid conversion from ‘void (*)(const CommandDescriptor&)’ to ‘void (*)(CommandDescriptor&)’ [-fpermissive]
In my understanding the reference to non-const object should be usable as argument to reference to const object parameter. So parameter with type pointer to function accepting non-const object reference should be more than satisfied with (and do implicit conversion from) argument of type pointer to function, which accepts even const object reference.
Where am I wrong?
void (*)(const CommandDescriptor&) and void (*)(CommandDescriptor&) are two completely different, unrelated types.
There are very simple rules regarding const: X* can be converted to X const*, X** can be converted to X const * const * and so on. Same thing with references. Nothing else is allowed.
Note that the rules do not allow to arbitrarily add or remove const at any position in the type, for example, X** cannot be converted to X const **. This is true also for the position of function arguments: you just cannot add or remove const there to get a compatible type.
Could these rules be extended so that they accommodate cases like yours and remain consistent? Probably so. But they are not.
C++ has a limited set of situations where const can be added or removed implicitly. You ran into one where it cannot be done. The reason why not is probably as simple as "describing those cases which are safe would be hard, and standards writers are lazy and conservative".
As a work around, you can do this:
CommandLogFilter bob(
logServer,
parent,
[](CommandDescriptor &descriptor) {
return printCommandReceived(descriptor);
}
);
as stateless lambdas can implicitly convert-to a pointer to a function matching their signature.
I don't like having to make the signature explicit there, but there is no way to do something similar with template "auto" lambdas and have the signature deduced unfortunately.
I've cut down some C++ 11 code that was failing to compile on Visual Studio 2015 to the following which I think should compile (and does with clang and gcc):
#include <utility>
void test(const char* x);
int main()
{
const char x[] = "Hello world!";
test(std::forward<const char*>(x));
}
I understand the call to forward isn't necessary here. This is cut down from a much more complex bit of code that decays any arrays in a variadic argument down to pointers and forwards everything on. I'm sure can find ways to work around this with template specialization or SFINAE, but I'd like to know whether it's valid C++ before I go down that road. The compiler is Visual Studio 2015, and the problem can be recreated on this online MSVC compiler. The compile error is:
main.cpp(13): error C2665: 'std::forward': none of the 2 overloads could convert all the argument types
c:\tools_root\cl\inc\type_traits(1238): note: could be '_Ty &&std::forward<const char*>(const char *&&) noexcept'
with
[
_Ty=const char *
]
c:\tools_root\cl\inc\type_traits(1231): note: or '_Ty &&std::forward<const char*>(const char *&) noexcept'
with
[
_Ty=const char *
]
main.cpp(13): note: while trying to match the argument list '(const char [13])'
Update:
#Yakk has suggested an example more like this:
void test(const char*&& x);
int main()
{
const char x[] = "Hello world!";
test(x);
}
Which gives a more informative error:
main.cpp(7): error C2664: 'void test(const char *&&)': cannot convert argument 1 from 'const char [13]' to 'const char *&&'
main.cpp(7): note: You cannot bind an lvalue to an rvalue reference
Again, this compiles on gcc and clang. The compiler flags for Visual C++ were /EHsc /nologo /W4 /c. #Crazy Eddie suggests this might be down to a VC++ extension to pass temporaries as non const references.
To me this looks like a bug in MSVC where it tries to be clever with array-to-pointer and gets it wrong.
Breaking down your second example:
The compiler needs to initialize a const char*&& from an lvalue of type const char[13]. To do this, 8.5.3 says it creates a temporary of type const char* and initializes it with the const char[13], then binds the reference to the temporary.
Initializing a const char* from a const char[13] involves a simple array-to-pointer conversion, yielding a prvalue of const char* which is then copied into the temporary.
Thus the conversion is well defined, despite what MSVC says.
In your first example, it's not test() that is causing the issue, but the call to std::forward. std::forward<const char*> has two overloads, and MSVC is complaining neither is viable. The two forms are
const char*&& std::forward(const char*&&);
const char*&& std::forward(const char*&);
One takes an lvalue reference, one takes an rvalue reference. When considering whether either overload is viable, the compiler needs to find a conversion sequence from const char[13] to a reference to const char*.
Since the lvalue reference isn't const (it's a reference to a pointer to a const char; the pointer itself isn't const), the compiler can't apply the conversion sequence outlined above. In fact, no conversion sequence is valid, as the array-to-pointer conversion requires a temporary but you can't bind non-const lvalue references to temporaries. Thus MSVC is correct in rejecting the lvalue form.
The rvalue form, however, as I've established above, should be accepted but is incorrectly rejected by MSVC.
I believe std::decay<const char []>::type is what you're looking for http://en.cppreference.com/w/cpp/types/decay
I think it should compile, but why are you bothering to use std::forward?
Isn't the correct solution simply to replace
std::forward<const char*>(x)
with:
(const char*)x
or for the generic case, replace:
std::forward<decay_t<decltype(x)>>(x)
with:
decay_t<decltype(x)>(x)
Using std::forward doesn't seem to have any purpose here, you have an array, you want to decay it to a pointer, so do that.
when I have both of these signatures, I get a compile error:
String& operator+(String&& a, const TCHAR* b)
String operator+(String a, const TCHAR* b)
string.cpp(97): error C2593: 'operator +' is ambiguous
string.cpp(34): could be 'String &operator +(String &&,const TCHAR *)'
string.cpp(24): or 'String operator +(String,const TCHAR *)'
Aren't they different????? I feel like performance could be increased if I could use both. On the other hand, is this ambiguous because the + operator always deals with rvalues?
vc++ 2010 compiler
The problem is that those are different signatures, but all arguments that can be used with one can also be used with the other, so the compiler cannot possibly disambiguate what function needs to be called depending on the arguments.
You probably meant to provide two overloads that take an rvalue-reference and and lvalue-reference respectively. Also note that it probably makes no sense to return a reference from the first overload.
Note that using an rvalue and lvalue reference overloads is only needed if you really need to distinguish between the two use cases, but the general definition of operator+ does not require that distinction, as it does not modify the arguments. The common way of implementing operator+ is:
T operator+( T lhs, T const & rhs ) {
return lhs+=rhs;
}
Performance can be improved a bit to allow for moves on either the first or the second arguments to operator+, but that requires 4 different combinations of lvalue/*rvalue* in both positions (lvalue+*lvalue; lvalue+*rvalue*; rvalue+*lvalue*; rvalue+*rvalue*)
I get the error from xcode (3.2.4)/gcc(4.0):
/Users/admin/scm/audacity/mac/../src/toolbars/DeviceToolBar.cpp: In member function 'void DeviceToolBar::ShowInputDialog()':
/Users/admin/scm/audacity/mac/../src/toolbars/DeviceToolBar.cpp:817: error: no matching function for call to 'DeviceToolBar::ShowComboDialog(wxChoice*&, wxString)'
/Users/admin/scm/audacity/mac/../src/toolbars/DeviceToolBar.h:74: note: candidates are: void DeviceToolBar::ShowComboDialog(wxChoice*, wxString&)
So it looks like it expects a reference to a pointer in ShowComboDialog, but I don't know why as the signatures are clearly normal pointers. Furthermore if it was expecting a reference to a pointer the way I am calling it should work.
This is the first error, and there are no special warnings before it.
Also, this compiles in MSVC 2008 express.
Please give me a clue.
//in the class def
//(only relevant portions included
class DeviceToolBar:public ToolBar {
public:
DeviceToolBar();
virtual ~DeviceToolBar();
void ShowInputDialog();
private:
void ShowComboDialog(wxChoice *combo, wxString &title);
wxChoice *mInput;
};
//in the cpp file
void DeviceToolBar::ShowInputDialog()
{
ShowComboDialog(mInput, wxString(_("Select Input Device")));
}
void DeviceToolBar::ShowComboDialog(wxChoice *combo, wxString &title)
{
//...
}
The problem is not the first parameter; its the second. You're passing in a temporary wxString, but the function is expecting a reference. C++ will automatically convert a temporary to a const reference, but it cannot convert it to a reference. You need to make ShowComboDialog take a const reference as its second parameter.
Your ShowComboDialog takes a wxString by non-const reference and you are trying to pass a temporary object as an argument to this parameter. You can only bind const references to temporary objects.
You either need to change ShowComboDialog to take its second argument either by value (wxString) or by const reference (const wxString&) or you need to create a variable for the wxString that you create when you call the function and then pass (a reference to) that variable instead.