c++ implicitly convert function arguments via custom assignment operator - c++

I'm working on a project with is part C written and partly C++ written.
I got 2 Enums which basically represent the same, however one is wrapped inside a class and the other one is located at a global namespace due to C compatibility.
//C Code File
typedef enum
{
C_Enum_first = 0,
C_Enum_Second,
} C_Enum_T
//(obviously) C++ Code file
class CMyClass
{
public:
enum class CPP_Enum
{
first= 0,
second,
};
CPP_Enum& operator= ( const C_Enum_T& rhs);
}
Now I have a function at a global namespace scope with takes the Cpp Enum as an argument
bool FooFunc(const CMyClass::CPP_Enum value);
However due to compatibility issues with C code there are some places where this function will be called with a C Enum value
bool res = FooFunc(C_Enum_Second);
This gives me a no known conversion error.
Yes I know i can overload, but for demonstration purposes i only showed 1 enum argument. In reality there are 3 enums with will increase my needed overloads.
Why is my assignment operator not called? Do assignment operator not work implicitly on function arguments?
thx for your help
greets Julian :)

Do assignment operator not work implicitly on function arguments?
Your operator= is a member of CMyClass. It can be called like this:
CMyClass cmc;
C_Enum_t a;
CPP_Enum& x = (cmc = a);
But it will not be considered for implicit conversion from CMyClass to CPP_Enum. Consider to use a free function for the conversion instead. Also it is rather fishy that your operator= returns a reference. You didn't include the implementation, but returning a reference does not look right. What should it refer to?

Related

Why is this user-defined conversion not done?

Consider:
template<typename T>
struct Prop
{
T value;
operator T() { return value; }
};
int main()
{
Prop<float> p1 { 5 };
Prop<std::vector<float>> p2 { { 1, 2, 3 } };
float f1 = p1; // Works fine
float f2_1_1 = p2.value[0]; // Works fine
float f2_1_2 = p2[0]; // Doesn't compile
return 0;
}
Why doesn't the line marked as such compile? Shouldn't it perform implicit conversion using the supplied conversion operator into std::vector<>, so that the [] can be found?
There are (many) other questions on this site that ask variations on this question, but I couldn't find one that I think applies here. Does it have to do with std::vector being a template?
Implicit conversions are not considered for objects of member function calls, including the subscript operator overload.
Consider the consequences if that were allowed: Every single time any undeclared member function is called like this, the compiler would have to figure out all the types that the object can be converted to (note that any other otherwise unrelated type could have a converting constructor), and check if that has declared the missing member function. Not to mention how confusing that would be for the reader of the code (the conversion might be obvious in your conversion operator case, but not in the converting constructor case, and as far as I know, they are not otherwise treated differently).
So is there a notationally convenient way to get Prop to behave the way I want
You would have to define a member function for each of the member function of vector that you want to pass pass through transparently. Here is the subscript operator as an example:
auto operator[](std::size_t pos) {
return value[pos];
}
auto operator[](std::size_t pos) const {
return value[pos];
}
The problem is of course that all wrapped member functions must be explicitly declared. Another problem is arguments whose type depend on T. For example, vector::operator[] uses vector::size_type, which might not be defined for all T that you might use (certainly not for float). Here we make a compromise and use std::size_t.
A less laborious way of creating such "transparent" wrapper is inheritance. A publicly inheriting template would automatically have all the member functions of the parent and be implicitly convertible to it and can be referred by pointers and references of parent type. However, the transparency of such approach is a bit problematic mainly because ~vector is not virtual.
Private inheritance allows same wrapping as your member approach, but with much nicer syntax:
template<typename T>
struct Prop : private T
{
using T::operator[];
using T::T;
};
Note that inheritance approach prevents you from using fundamental types as T. Also, it makes the implicit conversion impossible (even with conversion operator) , so you cannot use Prop as T in free functions that expect T.
PS. Note that your conversion operator returns a value, so the vector must be copied, which may be undesirable. Consider providing reference versions instead:
operator T&&()&& { return *this; }
operator T&()& { return *this; }
operator const T&() const& { return *this; }
the same way that any of the
p2.size();
p2.begin();
p2.push_back(24);
// etc.
don't make sense to compile
also
p2[0];
which is equivalent with
p2.operator[](0);
doesn't make sense to compile\
If you want this behavior (i.e. for Prop<T> to borrow T members) there is a C++ proposal by Bjarne to add the dot operator to the language. I would work the same way that operator -> works for smart pointers. AFAIR it had a lot of controversy and so I wouldn't hold my breath for it.
A bit of background for the operator dot proposal—Bjarne Stroustrup
Operator Dot (R3) - Bjarne Stroustrup, Gabriel Dos Rei
Smart References through Delegation: An Alternative to N4477's Operator Dot - Hubert Tong, Faisal Vali
Alternatives to operator dot - Bjarne Stroustrup

C++: Can I make an assignment operator "explicit"

I am on the task to migrate the concept of error handling in a C++ class library. Methods that previously simply returned bool (success/fail) shall be modified to return a Result object which conveys a machine readable error code and a human readable explanation (and some more which does not matter here).
Walking through thousands of lines of code is error prone, therefore I try to get the best support from the compiler for this task.
My result class has - among other member methods - a constructor that constructs the result from a code and an assignment operator for the code:
class Result
{
public:
typedef unsigned long ResultCode;
explicit Result(ResultCode code); // (1)
Result& operator=(ResultCode code); // (2)
};
Remark: I would usually use an enum class for ResultCode which would solve my problems, but this is not an option. This is because the major design objective was to use Result in different libraries, each of which shall define its own set of result codes without requiring one big header file that defines all possible result codes for all libraries. In fact, each class shall be able to define local result codes so that the list of possible result codes can be obtained from the classes header. Thus the codes cannot be enumerated in Result, they must be defined by the classes using the Result class.
To avoid implicit conversions on
return true;
Statements in the client code, the constructor has been declared explicit. But in nesting method calls, another problem occurs. Say, I have a method
bool doSomething()
{
return true;
}
Which I am using in a function that returns a Result object. I want to forward result codes of nested calls
Result doSomethingElse
{
Result result = doSomething();
return result;
}
With the current implementation of Result's assignment operator, this is not going to give me a compiler error - the boolean return value of doSomething() is implicitly converted to unsigned long.
As I have read in the C++ documentation, only constructors and conversion operators may be declared explicit.
My questions
Why is explicit not allowed for assignment operators or other methods? IMO it would make a lot of sense to allow any method to be explicit as well.
Are there other solutions to prevent implicit type conversion for the assignment operator?
Your problem isn't in the class Result: you are explicitly creating a new instance of it, after all; explicit cannot forbid it.
I don't think you can forbid the implicit promotion bool -> long.
You can work around it. One way is to make ResultCode not be an integer type. then, it could have an explicit constructor. Something like
class ResultCode
{
unsigned long m_code;
public:
explicit ResultCode(unsigned long code) : m_code(code) {}
operator unsigned long () { return m_code; }
};
would allow you to use ResultCode anywhere you can use a unsigned int and create it as ResultCode res = 5 or return ResultCode(5) but not call a function expecting a ResultCode (such as the Result constructor!) with anything which is not a ResultCode already, nor do something like return 5 if the function must return a ReturnCode.
Otherwise you can use template overloadng to 'catch' anything not being an unsigned int and force it to be an error
typedef unsigned long ResultCode;
class Result
{
ResultCode m_par;
public:
template<typename T>
Result(T param) { static_assert(false); }
template<>
Result(ResultCode par): m_par(par) {}
};
int main()
{
ResultCode a = 5; //ok
//unsigned long a = 6; //also ok
//bool a = true; //error!
//int a = 7; //also error!!
Result b(a);
}
With the current implementation of Result's assignment operator, this is not going to give me a compiler error - the boolean return value of doSomething() is implicitly converted to unsigned long.
With respect to the code you posted; it does result in an error error: no viable conversion from 'bool' to 'Result', see here.
A minimal example showing the behaviour you see in the code would be required. There is likely other constructors or type with conversion in the actual code that have a material effect on your code.
On the explicitly asked questions...
Why is explicit not allowed for assignment operators or other methods?
explicit is only allowed where implicit conversion can take place, i.e. where the compiler would attempt to generate the conversion for you (there is a special case for bool). Such conversions are constructors and the conversion (or casting operators).
Marking the constructor or conversion operator as explicit prevents the compiler from making the conversions, hence, if you require the conversion, you need to be explicit about it - as a general motivation for why this is done, it makes the code more explicit in what it does. There is a trade-off, so judicious use should be applied in both cases. The general advice is to favour explicit when in doubt.
For example;
struct Result {
Result(long src); // can be marked explicit
operator long() const; // can be marked explicit
};
Are there other solutions to prevent implicit type conversion for the assignment operator?
The assignment operator has a particular for Result& operator=(Result&);. In the assignment itself, there are no conversion. To prevent the implicit creation of a Result for the assignment, the constructor(s) need to be marked explicit.
To prevent the Result from being created from a ResultCode, you can either not declare the method, or mark it as deleted;
Result& operator=(ResultCode code) = delete;

Syntax for using overloaded operator C++

This is an overloaded operator contained in a class:
inline operator const FOO() const { return _obj_of_type_FOO; }
I cannot for the life of me understand:
How I would invoke this operator?
What would be its return value?
[Secondary] Whether making it inline affects anything apart from efficiency?
That expression looks like a declaration of a conversion operator if Foo is a type and it is inside a class. The second const (the one closer to the opening curly bracket) means that the conversion can be called on const instances. Let us say the class is C. You can think of a conversion operator as a constructor outside a class. For example, you can't add constructors to the class std::string, but you can add a conversion operator to std::string to your classes. The result is that you can construct std::string from your class instance.
1) How to invoke the conversion operator: by constructing a value of type Foo from a C, for example:
Foo foo = c (where c is an instance of C, the class that declares the conversion operator). Mind you that the invocation of the conversion can happen implicitly. If you have, for example, void funOnFoo(Foo v); and an instace c of C, this might implicitly call operator const Foo: funOnFoo(c). Whether this actually does, depends on the usual things: Whether there are other overloads of funOnFoo, other conversions for C, etc.
2) The return value is const Foo
3) inline means the same thing as for any function, in particular, does not affect overload resolution

Must the C++ standard library support classes that are picky about who their friends are?

This question is easiest to illustrate with an example, so here goes:
Is code like the following guaranteed to be valid, and compile & run correctly?
(Not all implementations actually compile it correctly, but I'm wondering if that's a bug.)
#include <algorithm>
class Picky
{
friend
Picky *std::copy<Picky const *, Picky *>(Picky const *, Picky const *, Picky *);
Picky &operator =(Picky const &) { return *this; }
public:
Picky() { }
};
int main()
{
Picky const a;
Picky b;
std::copy<Picky const *, Picky *>(&a, &a + 1, &b);
return 0;
}
std::copy requires an output iterator ([algorithms.general]/p5); output iterators, among other things, require *r = o to be valid ([output.iterators], Table 108) - not just "valid sometimes" or "valid in some contexts".
Since for Picky *p, a;, *p = a isn't valid in most contexts, Picky * isn't a valid output iterator.
Hmm it'd be great if you could generalize your answer to other things
beyond the particular example I gave. Like, for example,
std::vector::push_back(T const &), or whatever.
Befriending a member function is an absolute no-no, because you aren't even guaranteed that there's a member function with that signature ([member.functions]/p2, which Stephan T. Lavavej calls the "STL Implementers Can Be Sneaky Rule"):
An implementation may declare additional non-virtual member function
signatures within a class:
by adding arguments with default values to a member function signature187 [Note: An implementation
may not add arguments with default values to virtual, global, or non-member functions. — end note];
by replacing a member function signature with default values by two or more member function signatures with equivalent behavior; and
by adding a member function signature for a member function name.
187 Hence, the address of a member function of a class in the C++ standard library has an unspecified type.
The code might compile if std::copy() does not call any other non-friend functions but I've yet to encounter any such implementation. And there is no requirement in the standard limiting HOW std::copy() achieves the required effect.
However, it does require a working and accessible assignment operator.

Overloaded constructor - constructur with bool argument has precedence

I recently came across a class like the following
class Foo {
public:
Foo(std::string msg) {}
private:
Foo(bool b) {}
};
I noticed that trying to create an object of this class by means of
Foo foo("blah");
causes a compilation error telling that Foo::Foo(bool) is private. Apparently, if the argument is not an actual std::string, the compiler prefers to use the constructor with the bool argument. On the other hand, if the private constructor is not given, above code compiles just fine.
Why is it that the "bool-constructor" has precedence over the "string-constructor" althogh the type of the passed argument does not fit to any of them? Is this just a matter of definition or does it have a deeper meaning and some good reason?
The reason has to do with conversion operator precedence. Each of the calls includes an implicit conversion
pointer -> std::string
pointer -> bool
In this case #1 is a user defined conversion and #2 is a language / compiler defined one. User defined conversions have a much lower precedence and hence the other conversion is preferred.
Edit
Here is a similar question which has a much more in depth explanation of the precedence checks involved
conversion precedence in c++