wrong argument conversion preferred when calling function - c++

I'm writing a program under MS Visual C++ 6.0 (yes, I know it's ancient, no there's nothing I can do to upgrade). I'm seeing some behavior that I think is really weird. I have a class with two constructors defined like this:
class MyClass
{
public:
explicit MyClass(bool bAbsolute = true, bool bLocation = false) : m_bAbsolute(bAbsolute), m_bLocation(bLocation) { ; }
MyClass(const RWCString& strPath, bool bLocation = false);
private:
bool m_bAbsolute;
bool m_bLocation;
};
When I instantiate an instance of this class with this syntax: MyClass("blah"), it calls the first constructor. As you can see, I added the explicit keyword to it in the hopes that it wouldn't do that... no dice. It would appear to prefer the conversion from const char * to bool over the conversion to RWCString, which has a copy constructor which takes a const char *. Why does it do this? I would assume that given two possible choices like this, it would say it's ambiguous. What can I do to prevent it from doing this? If at all possible, I'd like to avoid having to explicitly cast the strPath argument to an RWCString, as it's going to be used with literals a lot and that's a lot of extra typing (plus a really easy mistake to make).

Explicit will not help here as the constructor is not a part of the implicit conversion, just the recipient.
There's no way to control the preferred order of conversions, but you could add a second constructor that took a const char*. E.g:
class MyClass
{
public:
MyClass(bool bAbsolute = true, bool bLocation = false);
MyClass(const RWCString& strPath, bool bLocation = false);
MyClass(const char* strPath, bool bLocation = false);
private:
bool m_bAbsolute;
bool m_bLocation;
};

Andrew Grant provided the solution. I want to tell you why it doesn't work the way you tried. If you have two viable functions for an argument, then the one that matches the argument best is called. The second requires a user-defined conversion, while the first only needs a standard conversion. That is why the compiler prefers the first over the second.

If you don;t want to keep casting it, then it seems to me that you might have to make another ctor that takes a const char*.
That is what I would probably do in this situation.
(Not sure why you are making a ctor with a type that you aren't passing for most of its use.)
edit:
I see someone else already posted this while I was typing mine

Not sure why it should confuse a reference to a string and a bool? I have seen problems with a bool and an int.
Can you lose the default value for the first constructor - it may be that since this is making it the default constructor for MyClass() then it is also the default if it can't match the args

Your choices are to add a constructor that explicitly takes a const char *
MyClass(const char* strPath, bool bLocation = false); // Thanks Andrew Grant!
Or do
MyClass( string("blah") );
The compiler intrinsically knows how to make a const char * into a bool. It would have to go looking to see if, for any of the first-argument types of MyClass constructors, there's a constructor that will take the source type you've given it, or if it can cast it to a type that is accepted by any of the constructors of any of the first-argument types of your MyClass constructors, or... well, you see where this is going and that's only for the first argument. That way lies madness.

The explicit keyword tells the compiler it cannot convert a value of the argument's type into an object of your class implicitly, as in
struct C { explicit C( int i ): m_i(i) {}; int m_i; };
C c = 10;//disallowed
C c( 2.5 ); // allowed
C++ has a set of rules to determine what constructor is to be called in your case - I don't know from the back of my head but you can intuitively see that the default arguments lead towards ambiguity.
You need to think those defaults through.
You can fallback onto some static, named, construction methods. Or you can use a different class (which is not a bad choice from a design viewpoint). In either way, you let the client code decide which constructor to use.
struct C {
static C fromString( const char* s, const bool b = true );
static C fromBools( const bool abs = true, const bool b = true );
};
or
struct CBase {
bool absolute;
bool location;
CBase( bool abs=true, bool loc=true );
};
struct CBaseFromPath {
// makes 'absolute' true if path is absolute
CBaseFromPath( const char* s, const bool loc );
};

Are you certain that it really is calling the first constructor? Are you calling it with the string hard-coded, or is it hidden behind a #define? Are you sure that the #define is what you think it is? (Try compiling with the /Ef option to get the expanded preprocessor output, and see if the call looks like you'd expect it to look.)
EDIT: Based on this and other comments, my suggestion is to add another constructor for const char*. Is that feasible?

Related

lvalue and rvalue getter, is it possible to remove them?

Let's say we have this simple class
struct MyClass {
const std::string &getString() const & {
return m_string;
}
std::string getString() && {
return std::move(m_string);
}
private:
std::string m_string;
};
As we can see, the m_string acts as a non mutable variable in the sense that we cannot modify it.
This structure also preserve the fact that if we move one instance of MyClass to another, the m_string attribute will be moved as well.
Now, we are going to try to refactor the prior structure :
struct MyClass {
std::string m_string;
};
Here, we keeps the fact that we can access it or move it, but we lose the "immutability"... So I tried to write it like that :
struct MyClass {
const std::string m_string;
};
Here we get the immutability thing, however, we lose the potential optimization when we move the object...
So, is it possible to have a behavior similar to the first code, without writing all the getter?
EDIT: the std::string is just for example, but the idea must be usable with all kind of objects
So, is it possible to have a behavior similar to the first code, without writing all the getter?
I can't think of any.
Having said that, the overhead of writing getters and setters for member variables is not such a big burden that I would spend too much time thinking about it.
However, there are some who think that getters and setters of member variables don't add enough protection to a class to even worry about them. If you subscribe to that line of thinking, you can get rid of the getters and setters altogether.
I have used the "no getters and setters" principle for containers of data enough times that I find it natural in many use cases.
You can implement this behavior using a template wrapper type. It seems you want a type that works well with copy and move construction and assignment, but which only provides const access to the wrapped object. All you should need is a wrapper with a forwarding constructor, an implicit conversion operator and dereferencing operators (to force the conversion when implicit conversion doesn't work) :
template<class T>
class immutable
{
public:
template<class ... A>
immutable(A&&... args) : member(std::forward<A>(args)...) {}
public:
operator const T &() const { return member; }
const T & operator*() const { return member; }
const T * operator->() const { return &member; }
private:
T member;
};
This will work well with compiler generated copy and move construction and assignment. The solution is not 100% transparent however. The wrapper will implicitly convert to a reference to the wrapped type, if the context allows it :
#include <string>
struct foo
{
immutable<std::string> s;
};
void test(const std::string &) {}
int main()
{
foo f;
test(f.s); // Converts implicitly
}
But it will need an extra dereference to force the conversion in contexts where implicit conversion will not work :
int main()
{
foo f;
// std::cout << f.s; // Doesn't work
std::cout << *(f.s); // Dereference instead
// f.s.size(); // Doesn't work
f.s->size(); // Dereference instead
}
There was a proposal to add overloading of the . operator, which would allow most cases to work as intended, without a dereferencing. But I'm not sure what the current state of the proposal is.
The solution is to use std::shared_ptr<const std::string>. A shared pointer to a immutable object has value semantic. Copy-on-write can be achieved using shared_ptr::unique(). See Sean Parent presentation 47:46 https://youtu.be/QGcVXgEVMJg.
If only you are willing to declare the copy and defuslt ctor as =default and define the move ctor with const_cast cheat.
MyClass::Myclass()=default;
MyClass::Myclass(Myclass const&)=default;
MyClass::Myclass(Myclass && m)
: m_string{std::move(const_cast<std::string&>(m.m_string))}{};

C++ constructor with optional parameters

Hi I am new to C++ and I am trying to create a class hierarchy where each class represents a node in a schema document, think json-schema. Have a look at the representation of e.g. a string. A string can have three optional constraints
min_length
max_length
pattern
Furthermore a string is a type so it would make sense to have a base class representing a type from which all types (boolean, number, ...) inherit. Now, one way to achieve this is by writing something like
struct Type {
const std::string m_name;
Type(const std::string& name)
: m_name{name}
{}
virtual X Serialize() const {
//...
}
};
struct String : Type {
const int m_max_len;
const int m_min_len;
const std::string m_pattern;
String(int min_len, int max_len, const std::string& pattern)
: Type("string")
, m_min_len(min_len)
, m_max_len(max_len)
, m_pattern(pattern)
{}
X Serialize() const override {
// If min_length was not set then it should be omitted from the serialized output.
}
};
This String implementation would not make the constraints optional. What to do?
Options:
One could employ a strategy where the default constructor parameters where set to some "illegal" value like INT_MIN (which would work in this case because the length can not be negative) but that would not work in the general case. It could very well be that all possible integers a legal values, the same goes for the pattern parameter.
You do not want to have different constructors for every possible permutation of optional parameters. In this case there are three optional values which would yield 2^3 different constructors. Also it would not be possible for the compiler to distinguish between the constructors String(int min_length) and String(int max_length).
It would be possible to do something like
String(int* min_length = nullptr, int* max_length = nullptr, const std::string* nullptr)
but then you would have to use new/delete or give lvalues for the set parameters.
Finally each member could be a std::unique_ptr.
String(std::unique_ptr<int> min_value nullptr, std::unique_ptr<int> max_value = nullptr, std::unique_ptr<const std::string> pattern = nullptr)
but then you would end up with quite complicated calls when creating an instance of String. Also if implementing a container of Types which may have optional parameters of its own things quickly get out of hand.
Finally, the code must be compatible with C++14.
You can simply use std::optional:
String(const std::optional<int> &min_len, const std::optional<int> &max_len,
const std::optional<std::string> &pattern);
Type *type = new String(5, {}, std::nullptr); // last 2 parameters are omitted.
For C++14 you can use similar constructs that exist in other open source libraries, (e.g. boost::optional, folly::Optional).
I lack reputation points to comment on #Kostas
To be compatible with C++14 you can try experimental namespace which has optional (if it is available/works on your compiler)
#include <experimental/optional>
then you can use
String(std::experimental::optional<int> &min_len,.....)
min_len.value_or(-1)
You can write your own class that can contain value or not if you can't use std::optional. It is not like lot of code. Can make its interface like std::optioal has or can make something different, what matters is data:
class OptInt {
bool set_;
int value_;
public:
OptInt() : set_(false) , value_(0) {}
OptInt(int v) : set_(true), value_(v) {}
// can add other ways how to create it
bool isSet() const {return set_;}
int get() const {if (!set_) throw 666; return value_;}
// can add other operations you want to it.
};
Then you can use such default-constructed OptInt as your default argument and so it will be not set, but if caller provides int argument then it will be set.
Have you tried to use an std::optional (since C++17)?
I know you mentioned the need to use C++14 compatible code, but there is a boost::optional available.

Can I delete function for an rvalue version of object?

For legacy reasons, there's a lot of usage of const char* in the code I'm working on. I am trying to limit that, and stumbled on something I'd like to know. I have something like:
class AClass {
public:
const char* getValue() { return _value.c_str(); }
private:
std::string _value;
}
But this class now may be returned by copy, eg. by function:
AClass getAClass();
We also might wanna pass that to something like this:
void functionFromOtherLibrary(const char* value);
Now thinking about that, this might cause an error:
functionFromOtherLibrary(getAClass().getValue());
since the intermediate is eligible to be destroyed at that point. Even if the above goes OK, because it's one statement, this probably won't:
const char* str = getAClass().getValue();
functionFromOtherLibrary(str);
So I was thinking of writing something like:
class AClass {
public:
const char* getValue() { return _value.c_str(); }
const char* getValue() && = delete;
}
to forbid calls for that method on rvalues. Just trying that gave me:
error C2560: cannot overload a member function with ref-qualifier with a member function without ref-qualifier
I'm not sure if this:
is valid construct and
is ever necessary. I've seen a lot of code that returns const char*s and it always seems to rely on the fact that the object returning the value will still exist and hold the source std::string.
I would really appreciate a more detailed explanation what happens when code uses std::strings to hold strings but only communicates with C strings.
And if you want to suggest removing C strings - that's what I'm trying to do right now. I still want an answer though.
You can't overload a function with a ref-qualifier with a function without a ref-qualifier. The MSVC error text is nice and clear on this point.
But you can just add the ref-qualifier to the other one:
class AClass {
public:
const char* getValue() & { return _value.c_str(); }
const char* getValue() && = delete;
};
Whether this is the right design or not is a separate question - but if you decide that it is, this is how you would do it.

overloading operator .

Ok, I know that operator. is not overloadable but I need something like that.
I have a class MyClass that indirectly embeds (has a) a std::string and need to behave exactly like a std::string but unfortunately cannot extend std::string.
Any idea how to achieve that ?
Edit: I want that the lines below to compile fine
MyClass strHello1("Hello word");
std::string strValue = strHello1;
const char* charValue = strHello1.c_str();
As per your later edit, that:
MyClass strHello1("Hello word");
std::string strValue = strHello1;
const charValue = strHello1.c_str();
should compile fine, the only solution is to write a wrapper over std::string:
class MyClass
{
private:
std::string _str;
public:
MyClass(const char*);
//... all other constructors of string
operator std::string& ();
//... all other operators of string
const char* c_str();
//... all other methods of string
friend std::string& operator + ( std::string str, Foo f);
};
//+ operator, you can add 2 strings
std::string& operator + ( std::string str, Foo f);
This however is tedious work and must be tested thoroughly. Best of luck!
You can overload the conversion operator to implicitly convert it to a std::string:
class MyClass
{
std::string m_string;
public:
operator std::string& ()
{
return m_string;
}
};
If you're not interested in polymorphic deletion of a string*, you can derived from std::string, just getting the behavior of your class behaving "as-a" std::string. No more, no less.
The "you cannot derived from classes that don't have a virtual destructor" litany (if that's the reason you say you cannot extend it) it like the "dont use goto", "dont'use do-while" "don't multiple return" "don't use this or that feature".
All good recommendation from and for people that don't know what they are doing.
std::string doesn't have a virtual destructor so don't assign new yourcalss to a std::string*. That's it.
Just make your class not having a virtual destructor itself and leave in peace.
Embedding a string and rewriting all its interface just to avoid inheritance is simply stupid.
Like it is stupid writing dozens of nested if to avoid a multiple return, just as its stupid introduce dozens of state flags to avoid a goto or a break.
There are cases where the commonly considered weird things must be used. That's why those things exist.
You can extend an interface without publically deriving from it. This prevents the case of problematic polymorphic destruction (aka no virtual destructor):
#include <iostream>
#include <string>
using namespace std;
class MyClass
: private std::string
{
public:
MyClass(const char* in)
: std::string(in)
{}
// expose any parts of the interface you need
// as publically accessible
using std::string::c_str;
using std::string::operator+=;
};
int main()
{
MyClass c("Hello World");
cout << c.c_str() << "\n";
c += "!";
cout << c.c_str() << "\n";
// Using private inheritance prevents casting, so
// it's not possible (easily, that is) to get a
// base class pointer
// MyClass* c2 = new MyClass("Doesn't work");
// this next line will give a compile error
// std::string* pstr = static_cast<MyClass*>(c2);
// delete c2;
}
Trying to sum-up all the discussions, it looks like you will never find a suitable dolution because ... your requirements are in cotraddiction.
You want you class to behave as ats::string
std::string behave as a value but
a value does not "change" when accessed but (think to c = a+b: do you expect a and b to change their value ??) ...
when accessing your "value" you want to change it.
If what I summed up collecting all the peaces (suggestion: edit your question otherwise all the answerer will risk to be lost) is correct you are in trouble with 3 & 4 (note the 3. derives from the concept of "assignment", and you can do noting to change it, while 4. comes from you directly)
Now, I can try to reverse-engineer your psychology (because you didn't provide good information about what your class represent and why you cannot "extend" a string) I can find
two possibility neither of which will fit all the above requirements.
Store a string into your class and make your class to behave as a std::string. There are threee ways to come to this point:
a. embed a string and make your class to decay to it:
essentially your class must contain
.
operator std::string&() { return my_string; } //will allow l-value assignments
operator const std::string&() const { return my_string; } //will allow r-value usage
const char* c_str() const { return my_string.c_str(); }
b. derive from std::string. In fact that's like having an anonymous my_string in it, which "decay" operations implicit. Not that different as above.
c. embed or privately derive, and rewrite the std::string interface delegating the std::string functions. It's just a long typing to get exactly the b. result. so what the f..k? (this last question is dedicated to all the ones that believe a. or b. will break encapsulation. c. will break it as well, it will only take longer!)
Don't store a string, but just get it as a result from a calculation (the "lookup" you talk about, not clarifying what it is).
In this last case, what you need is a class that decay automatically into std::string as a value.
So you need, in your class
operator std::string() const { return your_lookup_here; }
note that const is necessary, but there is no need to modify your class inner state, since the resulting string is not stored.
But this last solution has a problem with const char*: since the string is temporary, until you don't assign it, its buffer is temporary as well (will be destroyed) so decaying into const char* to assign the pointer is clueless (the pointer will point to a dead buffer).
You can have a
const char* c_str() const { return std::string(*this).c_str(); } //will call the previous one
but you can use this only into expressions or a pass-through parameter in function calls (since the temporary will exist until the evaluating expression is fully evaluated), not in an assignment towards an l-value (like const char* p; p = myclassinstace.c_str(); )
In all of the above cases (all 1.) you also need:
myclass() {}
myclass(const std::string& s) :my_string(s) { ... }
myclass(const char* s) :my_string(s) { ... }
or - in C++11, just
template<class ...Args>
myclass(Args&&... args) :my_string(std::forward<Args...>(args...)) {}
In case 2., instead of initialize the not existent my_sting, you should use the arguments to set what you will look up (we don't know what it is, since you did not tell us)
Hope in all these option you can find something useful.
You can add an operator const reference to string, as follows:
class C
{
public:
// Implicit conversion to const reference to string (not advised)
operator const std::string &() const
{
return s_;
}
// Explicit conversion to a const reference to string (much better)
const std::string &AsString() const
{
return s_;
}
private:
std::string s_;
};
As you can see from the comments, it would be much better to add an explicit conversion function if you really need this behavior. You can read about why this is bad in the Programming in C++ Rules and Recommendations article.

Why is explicit allowed for default constructors and constructors with 2 or more (non-default) parameters?

I understand that constructors with one (non-default) parameter act like implicit convertors, which convert from that parameter type to the class type. However, explicit can be used to qualify any constructor, those with no parameters (default constructor) or those with 2 or more (non-default) parameters.
Why is explicit allowed on these constructors? Is there any example where this is useful to prevent implicit conversion of some sort?
One reason certainly is because it doesn't hurt.
One reason where it's needed is, if you have default arguments for the first parameter. The constructor becomes a default constructor, but can still be used as converting constructor
struct A {
explicit A(int = 0); // added it to a default constructor
};
C++0x makes actual use of it for multi parameter constructors. In C++0x, an initializer list can be used to initialize a class object. The philosophy is
if you use = { ... }, then you initialize the object with a sort of "compound value" that conceptually represents the abstract value of the object, and that you want to have converted to the type.
if you use a { ... } initializer, you directly call the constructors of the object, not necessarily wanting to specify a conversion.
Consider this example
struct String {
// this is a non-converting constructor
explicit String(int initialLength, int capacity);
};
struct Address {
// converting constructor
Address(string name, string street, string city);
};
String s = { 10, 15 }; // error!
String s1{10, 15}; // fine
Address a = { "litb", "nerdsway", "frankfurt" }; // fine
In this way, C++0x shows that the decision of C++03, to allow explicit on other constructors, wasn't a bad idea at all.
Perhaps it was to support maintainance. By using explicit on multi-argument constructors one might avoid inadvertently introducing implicit conversions when adding defaults to arguments. Although I don't believe that; instead, I think it's just that lots of things are allowed in C++ simply to not make the language definition more complex than it already it is.
Perhaps the most infamous case is returning a reference to non-static local variable. It would need additional complex rules to rule out all the "meaningless" things without affecting anything else. So it's just allowed, yielding UB if you use that reference.
Or for constructors, you're allowed to define any number of default constructors as long as their signatures differ, but with more than one it's rather difficult to have any of them invoked by default. :-)
A better question is perhaps, why is explicit not also allowed on conversion operators?
Well it will be, in C++0x. So there was no good reason why not. The actual reason for not allowing explicit on conversion operators might be as prosaic as oversight, or the struggle to get explicit adopted in the first place, or simple prioritization of the committee's time, or whatever.
Cheers & hth.,
It's probably just a convenience; there's no reason to dis-allow it, so why make life difficult for code generators, etc? If you checked, then code generation routines would have to have an extra step verifying how many parameters the constructor being generated has.
According to various sources, it has no effect at all when applied to constructors that cannot be called with exactly one argument.
According to the High Integrity C++ Coding Standard you should declare all sinlge parameter constructor as explicit for avoiding an incidentally usage in type conversions. In the case it is a multiple argument constructor suppose you have a constructor that accepts multiple parametres each one has a default value, converting the constructor in some kind of default constructor and also a conversion constructor:
class C {
public:
C( const C& ); // ok copy
constructor C(); // ok default constructor
C( int, int ); // ok more than one non-default argument
explicit C( int ); // prefer
C( double ); // avoid
C( float f, int i=0 ); // avoid, implicit conversion constructor
C( int i=0, float f=0.0 ); // avoid, default constructor, but
// also a conversion constructor
};
void bar( C const & );
void foo()
{
bar( 10 ); // compile error must be 'bar( C( 10 ) )'
bar( 0.0 ); // implicit conversion to C
}
One reason to explicit a default constructor is to avoid an error-prone implicit conversion on the right hand side of an assignment when there is an overload to class_t::operator= that accepts an object with type U and std::is_same_v<U, class_t> == false. An assignment like class_t_instance = {} can lead us to an undesirable result if we have, for example, an observable<T> that overloads the move assignment operator to something like observable<T>::operator=(U&&), while U should be convertible to T. The confusing assignment could be written with an assignment of a default constructed T (observed type object) in mind, but in reality the programmer is "erasing" the observable<T> because this assignment is the same as class_t_instance = class_t_instance{} if the default constructor is implicit. Take a look at a toy implementation of an observable<T>:
#include <boost/signals2/signal.hpp>
#include <iostream>
#include <type_traits>
#include <utility>
template<typename T>
struct observable {
using observed_t = T;
//With an implicit default constructor we can assign `{}` instead
//of the explicit version `observable<int>{}`, but I consider this
//an error-prone assignment because the programmer can believe
//that he/she is defining a default constructed
//`observable<T>::observed_t` but in reality the left hand side
//observable will be "erased", which means that all observers will
//be removed.
explicit observable() = default;
explicit observable(observed_t o) : _observed(std::move(o)) {}
observable(observable&& rhs) = default;
observable& operator=(observable&& rhs) = default;
template<typename U>
std::enable_if_t<
!std::is_same_v<std::remove_reference_t<U>, observable>,
observable&>
operator=(U&& rhs) {
_observed = std::forward<U>(rhs);
_after_change(_observed);
return *this;
}
template<typename F>
auto after_change(F&& f)
{ return _after_change.connect(std::forward<F>(f)); }
const observed_t& observed() const noexcept
{ return _observed; }
private:
observed_t _observed;
boost::signals2::signal<void(T)> _after_change;
};
int main(){
observable<int> o;
o.after_change([](auto v){ std::cout << "changed to " << v << std::endl; }); //[1]
o = 5;
//We're not allowed to do the assignment `o = {}`. The programmer
//should be explicit if he/she desires to "clean" the observable.
o = observable<int>{};
o = 10; //the above reaction [1] is not called;
//outputs:
//changed to 5
}