I have a class, X, and it has the following constructors:
class X{
X(int64_t, int16_t, bool, int8_t);
X(int64_t, int16_t, bool);
X(double);
X(double, FT);
explicit X(const string&);
X(const string&, Y);
};
The problem is the compiler once created an X object passing just a bool (presume it was the double constructor which allowed this?) and it caused an issue.
To prevent this I made the bool constructor explicit and deleted it:
explicit X(bool) = delete;
but now I get compiler errors:
EXPECT_EQUALS(X("9.8901099"), a/b);
EXPECT_EQUALS(X{"56267"}, x);
X x{"-56267E-1"};
X b("5");
where the compiler says I have made use of deleted function explicit X(bool) = delete
How do I prevent an object of X being created from a bool?
This happens because bool is a better match for const char[] than std::string. When you have no ctor accepting bool then the std::string one is chosen. When you have a ctor with bool then this overload is selected. Only it is deleted so it is illegal to call it.
Lets see this behavior with a simple free overloaded function:
auto foo(int) { cout << "foo int" << endl; }
auto foo(std::string const &) { cout << "foo string" << endl; }
auto main() -> int {
foo(3); // int
foo("Asdf"); // std::string
}
When you add a bool overload:
auto foo(int) { cout << "foo int" << endl; }
auto foo(std::string const &) { cout << "foo string" << endl; }
auto foo(bool) { cout << "foo bool" << endl; }
auto main() -> int {
foo(3); // int
foo("Asdf"); // bool (also warning implicit conversion turn string literal into bool)
}
The solution is to add a char const * overload:
auto foo(int) { cout << "foo int" << endl; }
auto foo(std::string const &) { cout << "foo string" << endl; }
auto foo(char const *s) {
cout << "foo char const *" << endl;
// possibly:
return foo(std::string{s});
}
auto foo(bool) = delete;
auto main() -> int {
foo(3); // int
foo("Asdf"); // char const *
foo(true); // error
}
Because some legacy code uses and returns char * instead of char const * you might need to add a char * overload too.
First, you need to understand what happens if you explicitly delete the bool constructor. It becomes available in overload selection and when it is the best match it becomes used, giving a compiler error then because it is deleted.
This is different from when you do not define it, in that you can indeed 'stop' boolean values from converting via an implicit conversion plus followed by a (different) constructor of your class X, because it is the best match for a boolean, so implicit conversions stop there.
Consider the usage of your class
X x("abc");
Without the deleted bool constructor, this selects X(const string&).
With the deleted bool constructor, however, this will select the explicit X(bool), which is also deleted so this gives a compiler error. The solution to this, as Kerrek SB said, is to define a constructor for const char * as well.
And indeed, if you don't delete the bool constructor then the following selects the double
X x(true);
via first conversion to int and then conversion to double.
So, you can choose either solution, to delete or not to delete, but you need to be aware of the consequences and the requirements. If you delete it, you need to supply a const char * constructor. If you don't delete it, then you need to live with the fact that bool can be used to construct an instance of your class.
Related
I'm debugging an issue in a large C++ codebase where an attribute of a struct is occasionally being changed to a bad value. Unfortunately, the attribute is public and is accessed or changed in hundreds of places, so simply adding a breakpoint on a mutator is not possible. Also, I don't know the instance of the struct, so adding an address watchpoint wouldn't help.
Instrumenting the code would be a major job. However, a colleague helpfully suggested creating a proxy class which could wrap the existing type in the struct declaration. For example, instead of using MyType _type I would replace this with ChangeProxy<MyType> _type in the struct and the application should compile and work with the proxy taking the place of the direct type in the same manner as, for example, a smart pointer.
However, when I build an example, the implicit conversion operation in the template class doesn't appear to get invoked in type deduction. Here's the code:
#include <iostream>
class MyType {
long _n = 0;
public:
MyType() {}
MyType(const long n) : _n{n} {}
MyType& operator=(const long n) { _n = n; return *this; }
bool isZero() const { return _n != 0; }
};
template <class T>
class ChangeProxy {
public:
ChangeProxy() {}
ChangeProxy(const T& t) : _t{t} {}
ChangeProxy(const T&& t) : _t{std::move(t)} {}
ChangeProxy& operator=(const T& t) {onChange(t); _t = t; return *this;}
ChangeProxy& operator=(const T&& t) {onChange(t); _t = std::move(t); return *this;}
operator T() {return _t;}
private:
T _t;
void onChange(const T& newVal) { /* something here to notify me of changes */ };
};
struct MyStruct {
// MyType _type; // this works ...
ChangeProxy<MyType> _type; // .. but this doesn't
};
int main() {
MyStruct i;
std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
i._type = 1;
std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
return 0;
}
Unfortunately, when I build this I get the following errors:
proxy-variable~test.cpp:35:73: error: ‘class ChangeProxy<MyType>’ has no member named ‘isZero’
35 | std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
| ^~~~~~
proxy-variable~test.cpp:37:73: error: ‘class ChangeProxy<MyType>’ has no member named ‘isZero’
37 | std::cout << "i._type.isZero() : " << std::boolalpha << i._type.isZero() << std::endl;
| ^~~~~~
So it seems that the compiler isn't deducing that it can cast a ChangeProxy<MyType> to a MyType. What have I done wrong here?
The context here doesn't let the compiler try out implicit conversions. Calling a member function on some object never does. You can force this by e.g.
std::cout << "i._type.isZero() : " << std::boolalpha <<
static_cast<MyType>(i._type).isZero() << '\n';
// ^^^^^^^^^^^^^^^^^^^ Here, enforce conversion
Another option would be:
MyStruct i;
const MyType& underlying = i._type; // Again, request conversion manually
std::cout << underlying.isZero() << '\n';
What you are doing is invoking a method on the class ChangeProxy<MyType> which indeed doesn't have any method isZero() defined on it, hence the compilation error. You could probably add something like
T const& operator()() const {return _t;}
And then call it using
i._type().isZero()
The reason that the wrapped i._type.isZero() can never work is that implicit conversions of the i._type object aren't considered for direct method calls, and you can't overload operator. like you can operator->.
It's nothing to do with type deduction, there's simply no mechanism in the language to do what you want.
Luckily, you're solving the wrong problem anyway.
... a colleague helpfully suggested creating a proxy class which could wrap the existing type in the struct declaration
Hmm, you didn't mention that here - or am I a colleague now?
an attribute of a struct is occasionally being changed to a bad value
Which attribute? Be specific!
In your code, you're treating the MyType instance as the problematic attribute. However, the only state in MyType is its long _n member.
Writing
class MyType {
ChangeProxy<long> _n = 0;
which is what I actually suggested when I referred to wrapping built-in types, avoids this problem entirely. You may of course need operator!= to make isZero work, but that's a normally overloadable operator.
Oddly the code in your question doesn't permit any mutation of _n anyway, so it's unclear how it can be getting a bad value. However, I assume this is just an artefact of a simplified example.
Here is some class with two overloaded methods foo:
class Object {
public:
Object (double someVal) : val(someVal) { }
double getter () const { return val; }
double& getter () { return val; }
private:
double val;
};
So now the double Object::getter() const function will be called on const instances
const Object instance(42);
cout << instance.getter() << endl; // called: `double getter() const`
Now, I am trying to get reference to double getter() const function and assign it to std::function type
const Object instance(42);
function<double(const Object&)> foo = &Object::getter;
cout << foo(instance) << endl;
The code works fine if function double& getter() is removed, but with it I got the following error on the second line:
test.cpp:18:34: error: no viable conversion from '<overloaded function type>' to
'function<double (const Object &)>'
function<double(const Object&)> foo = &Object::getter;
^ ~~~~~~~~~~~~~~~
It seems that error happens, because system tries to call double& getter().
The question is how to force calling of double getter() const?
The full listing is attached here
By casting to the specific function pointer type:
std::function<double(const Object&)> foo = static_cast<double(Object::*)() const>(&Object::getter);
Just use a lambda closure:
Object o{0.0};
std::function<double()> f = [o](){ return o.getter(); };
The lambda calls the const version of getter(), as captured variables are const by default (otherwise you'd have to use mutable).
Address of Overload functions defined 7 contexts where the correct overload can be deduced. Yet std::function<...> is not one of them. Thus, the overload function to get address of is ambiguous.
There are a few ways to select the overload you want:
const Object instance(42);
// Use static_cast to select overload
std::function<double(const Object&)> foo = static_cast<double(Object::*)() const>(&Object::getter);
// Use lambda to select overload
// std::function type parameters can be omitted since c++ 17
// Guaranteed copy elision since c++ 17
std::function bar = [](const Object& instance) { return instance.getter(); };
// Use std::mem_fn
std::function<double(const Object&)> mfn = std::mem_fn<double() const>(&Object::getter);
However, an idiomatic way to declare methods with similar functionality but differed by constness is actually to declare two different functions: foo() and cfoo(). Think about begin() and cbegin(). The latter returns a const iterator.
You can use a typedef to disambiguate the function you want:
#include <iostream>
#include <functional>
class Object {
public:
Object (double someVal) : val(someVal) { }
double getter () const { return val; }
double& getter () { return val; }
private:
double val;
};
typedef double (Object::*funtype)() const;
int main()
{
const Object instance(42);
std::function<double(const Object&)> foo = static_cast<funtype>(&Object::getter);
std::cout << foo(instance) << std::endl;
}
run on cpp.sh
Or, without casting:
#include <iostream>
#include <functional>
class Object {
public:
Object (double someVal) : val(someVal) { }
double getter () const { return val; }
double& getter () { return val; }
private:
double val;
};
typedef double (Object::*funtype)() const;
int main()
{
const Object instance(42);
funtype temp = &Object::getter;
std::function<double(const Object&)> foo = temp;
std::cout << foo(instance) << std::endl;
}
run on cpp.sh
Yet another example, going through some options.
// auto mem_fn = static_cast<double (Object::*)() const>(&Object::getter);
// or shorter:
double (Object::*mem_fn)() const = &Object::getter;
// store member function (without instance)
std::function<double(const Object&)> foo = mem_fn;
std::cout << foo(instance) << "\n";
// bind with instance
auto bound = std::bind(mem_fn, &instance);
std::cout << bound() << "\n";
// store member function (with instance)
std::function<double()> bar = bound;
std::cout << bar() << "\n";
// store member function (with instance), without the intermediate steps
std::function<double()> baz =
std::bind(
static_cast<double (Object::*)() const>(&Object::getter),
instance
);
std::cout << baz() << "\n";
The following code calls a const method passing a reference to a member, which is then modified.
#include <iostream>
struct A {
int i;
A(int _x) : i(_x) { }
void calc(int& j, const int value) const { j = value; }
void set1() { calc(i, 1); }
};
int main()
{
A a(3);
std::cout << a.i << std::endl;
a.set1();
std::cout << a.i << std::endl;
return 0;
}
The code compiles with gcc 6.4.0, and with clang 5.0.2, with no warnings.
Is the code legal?
The const method calc is able to modify the object, when called from a non-const method.
const qualifier on a member function applies to the *this instance.
In calc(), this is a pointer to const A, but the parameter j is taken by non-const reference, so this is perfectly standard behaviour.
Now, if in calc you tried to assign to this->i, the code would not compile.
void A::calc(const int value) const
{
i = value; // Compilation error here: i is a data member of a const instance
}
In the same way, if set1 was made a const member function, then, the code would not compile (because it would try to bind this->i to a parameter taken by non-const reference)
Sure. Marking the method const just makes *this const, i.e. the function promises not to modify the object by writing through this.
It's still possible to modify the object through other means (assuming they're not marked const as well, such as int& j in your example).
Remember that having a "const pointer" like const Thing* or a "const reference" like const Thing& does NOT mean that the const-qualified object cannot change while you have the pointer/reference. It only means that you can't use that particular pointer/reference as a way of changing it. But there could be other names, pointers, or references that do allow changing it.
A couple of examples:
void f1(const int& arg1, int& arg2) {
std::cout << "arg1 before: " << arg1 << "\n";
arg2 = 4;
std::cout << "arg1 after: " << arg1 << "\n"; // same thing?
}
f1 might look as though it must always print the same value in the "before" and "after" lines. But not if someone passes the same int object to both arguments:
void call_f1() {
int n = 7;
f1(n, n); // Prints before 7, after 4!
}
Or if a function call comes between two uses of a const reference, that can similarly change a variable in some way:
void something_else();
void f2(const int& arg) {
std::cout << "arg before: " << arg << "\n";
something_else();
std::cout << "arg after: " << arg << "\n";
}
int n = 2;
void something_else() { n = 8; }
void call_f2() {
f2(n); // Prints before 2, after 8!
}
So it's true that in your void A::calc(int& j, const int value) const function, the this pointer is const A* const, which means you can't change the A object using the this pointer. But there can still be other ways to change it, like here you have an int& j reference to non-const object. If it so happens that j refers to a subobject of *this, then modifying j is a valid way of modifying the subobject of *this. This is similar to my f1 example above, where arg1 can't be used to change the referenced int, but arg2 can, and if they refer to the same int, this means arg1 has changed.
The case is slightly different when a variable is defined with the const qualifier in the first place. If we write
const A a(3);
then we do get a guarantee that (except during the constructor and destructor), the object can't be changed in any way. The language will usually prevent you from accidentally trying, like with a.set1(), but even if you try const_cast tricks, any actual change would then be undefined behavior.
There is nothing wrong with your code. Declaring a method const merely means that this is const. However, your method does not (directly) modify this or any members of this. Consider this contrived, albeit correct example:
struct foo {
int value;
void modify_const(foo& f) const { f.value = 5; }
};
int main() {
foo f;
f.value = 3;
f.modify_const(f);
}
The method does not modify this, and the parameter is declared as non-const, thus calling f.modify_const(f); on a const f will fail due to the parameter being passed as non-const.
Just shows you are never safe. A const qualifier doesn't guarantee the value can never change.
Try it like this, and you can do really nasty things:
#include <iostream>
class A {
const int i;
void calc(int& j, const int value) const { j = value; }
public:
A(int _x) : i(_x) { }
void set1() const { calc(*const_cast<int*>(&i), 1); }
int getI() const { return i; }
};
int main()
{
const A a(3);
std::cout << a.getI() << std::endl;
a.set1();
std::cout << a.getI() << std::endl;
return 0;
}
Can someone explain why the original object that is passed to a new object via std::move is still valid afterwards?
#include <iostream>
class Class
{
public:
explicit Class(const double& tt) : m_type(tt)
{
std::cout << "defaultish" << std::endl;
};
explicit Class(const Class& val) :
m_type(val.m_type)
{
std::cout << "copy" << std::endl;
};
explicit Class(Class&& val) :
m_type(val.m_type)
{
m_type = val.m_type;
std::cout << "move: " << m_type << std::endl;
};
void print()
{
std::cout << "print: " << m_type << std::endl;
}
void set(const double& tt)
{
m_type = tt;
}
private:
double m_type;
};
int main ()
{
Class cc(3.2);
Class c2(std::move(cc));
c2.print();
cc.set(4.0);
cc.print();
return 0;
}
It outputs the following:
defaultish
move: 3.2
print: 3.2
print: 4
I would expect the calls to cc.set() and cc.print() to fail...
UPDATE
Thanks to answers below, we've identified that 1) I wasn't moving anything in the move constructor, and 2) std::move() on an int or double doesn't do anything because it's more expensive to move these types than to simply copy. The new code below updates the class's private member variable to be of type std::string instead of a double, and properly calls std::move when setting this private member variable in the Class' move constructor, resulting in an output that shows how a std::move results in a valid but unspecified state
#include <iostream>
#include <string>
class Class
{
public:
explicit Class(const std::string& tt) : m_type(tt)
{
std::cout << "defaultish" << std::endl;
};
explicit Class(const Class& val) :
m_type(val.m_type)
{
std::cout << "copy" << std::endl;
};
explicit Class(Class&& val) : m_type(std::move(val.m_type))
{
std::cout << "move: " << m_type << std::endl;
};
void print()
{
std::cout << "print: " << m_type << std::endl;
}
void set(const std::string val )
{
m_type = val;
}
private:
std::string m_type;
};
int main ()
{
Class cc("3.2");
Class c2(std::move(cc));
c2.print( );
cc.print();
cc.set( "4.0" );
cc.print();
return 0;
}
And finally the output:
defaultish
move: 3.2
print: 3.2
print:
print: 4.0
Because the standard says so.
Moved-from objects have a valid but unspecified state. That means you can still use them, but you can't be sure what state they'll be in. They could look just as they did before the move, depending on what is the most efficient way to "move" data out of them. For example, "moving" from an int makes no sense (you'd have to do extra work to reset the original value!) so a "move" from an int is actually only ever going to be a copy. The same is true of a double.
Although in this case it's got more to do with the fact that you didn't actually move anything.
In the code example, std::move determines which constructor gets called. Nothing more. So c2(std::move(cc)) calls the move constructor for Class. The move constructor for Class doesn't do anything to its argument, so cc is unchanged, and it can be used just as it could have before the call to the move constructor.
All the talk in comments and answers about the state of an object that has been moved from is about the requirements on standard library types, which will be left in a "valid but unspecified state" (17.6.5.15, [lib.types.movedfrom]). What you do with your types is not affected by that.
EDIT: sigh. You edited the code and changed the question. Now that your class holds a std::string instead of a float things are different, and the std::string object in cc is, indeed, in a "valid but unspecified state".
There are 2 function overloads:
MyClass do_something(MyClass param);
const MyClass& do_something(const MyClass& param);
Then I do:
MyClass c1 {"c1"};
do_something(c1); // I want this to be used by value overload
do_something(c1); // this to be used by reference overload
Is there any special way to explicitly specify that argument is passed by value or by reference?
For move semantic there is std::move() I wonder if there is anything like std::copy() std::ref for my case?
P.S. It's not to be used in real program, just checking out by myself the difference of passing arguments, returning values and their behaviour in different ways and have all functions with the same name:
// pass by value (copy)
MyClass do_something(MyClass param) {
cout << "do_something(MyClass param)" << endl;
param.i = 100;
return param;
}
// !!! Your normal habit when passing an argument to a function should be to pass by const reference. (thinking in c++)
// pass by reference (reference)
const MyClass& do_something(const MyClass& param) { // doesn't allow to modify the object
cout << "do_something(MyClass& param)" << endl;
return param;
}
// pass by move semantic (move)
MyClass&& do_something(MyClass&& param) {
cout << "do_something(MyClass&& param)" << endl;
param.name += "__after_do_something(MyClass&& param)";
param.i = 100;
return move(param);
}
// pass by pointer (reference)
MyClass* do_something(MyClass* const param) { // allows to modify object, but not pointer (address)
cout << "do_something(MyClass* const param)" << endl;
param->i = 100;
// (*param).i = 100; // the same as above
return param;
}
You can resolve an overload ambiguity by casting to the relevant function pointer type (it's one of the rare cases where the type of an expression is determined by outer context, instead of being built up from inside):
struct MyClass { char const* s; };
MyClass do_something(MyClass) { return MyClass(); }
const MyClass& do_something(const MyClass& param) { return param; }
auto main() -> int
{
MyClass c1 {"c1"};
static_cast<MyClass(*)(MyClass)>( do_something )( c1 ); // Value overload
static_cast<MyClass const&(*)(MyClass const&)>( do_something )( c1 ); // Ref overload
}
But in practice you should just name the functions differently, or use tie-breaker arguments or argument types, i.e., designing the functions for explicit choice of function.
I would name them differently because they do different things, so it indicates the Wrong Thing™ to have the same name for them.
Is there any special way to explicitly specify that argument is passed by value or by reference?
No, but there are workaround.
With template method and specialization, you may explicitly tell which version you want:
template <typename T>
T do_something(T);
template<>
MyClass do_something(MyClass) { std::cout << "value" << std::endl; }
template<>
const MyClass& do_something(const MyClass&)
{
std::cout << "reference" << std::endl;
}
And then call it:
do_something<MyClass>(c); // value
do_something<const MyClass&>(c); // reference
do_something(c); // value
Live Demo
But it would be simpler/cleaner to create overload with explicit tag:
struct by_value{};
struct by_ref{};
MyClass do_something(MyClass, by_value) { std::cout << "value" << std::endl; }
const MyClass& do_something(const MyClass&, by_ref)
{
std::cout << "reference" << std::endl;
}
And call it
do_something(c, by_value{}); // value
do_something(c, by_ref{}); // reference
Is there any special way to explicitly specify that argument is passed by value or by reference?
Yes. If it is not copyable (i.e., deleted or private copy constructor) it can only be passed by reference.