Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

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

  1. 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.
  2. Are there other solutions to prevent implicit type conversion for the assignment operator?
like image 825
kritzel_sw Avatar asked Jul 19 '16 07:07

kritzel_sw


1 Answers

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);
}
like image 122
Francesco Dondi Avatar answered Sep 22 '22 06:09

Francesco Dondi