0

note: I am still new to c++, and while this may be a simple issue, yet I am unable to find a solution.

Purpose:

I would like to pass an empty string (as one would in java/C#) to my constructor. I receive an error:

error: no matching function for call to 'ReturnObject::ReturnObject(ResultCode::ClientCode, const char [1])'
         return new ReturnObject(ResultCode::ClientCode::enum_FailedOpeningClientSocket, "");

The ReturnObject's purpose is to encapsulate an enum and a string.

What does this error mean and how can I solve it?

I have attempted changing my constructor parameter from QString data to char data and calling with '' but that resulted in an error empty character constant.

calling code:

return new ReturnObject(ResultCode::ClientCode::enum_FailedSocketConnection, "");

header:

class ReturnObject
{
public:
    ReturnObject(ResultCode enum_code, QString data);

    QString getData();
    ResultCode getCode();

private:
    ResultCode e_code;
    QString data_string;

};

implementation

#include "returnobject.h"

ReturnObject::ReturnObject(){
    data_string="WARN";
}

ReturnObject::ReturnObject(ResultCode enum_code, QString data)
    : e_code(enum_code)
    , data_string(data)
{}

ResultCode ReturnObject::getCode()
{
    return e_code;
}

QString ReturnObject::getData()
{
    return data_string;
}

Thanks to wasthishelpful and a few comments, I made a tragic logic error which had me looking at the wrong parameter, the solution is that I should casting my enum class ResultCode which is the parent class to one of the nested classes, in this case ClientCode, as seen below from my enum class header

enum.h

#ifndef ENUMS_H
#define ENUMS_H

class ResultCode{
public:
    enum class LoginDialogCode{
        enum_LoginSuccess=0,
        enum_InternetOffline=1,
        enum_ServerOffline=2,
        enum_InvalidLoginPass=3,
        enum_EmptyLoginPass=4,
        enum_FailedRetreivingServerList=5,
        enum_TokenFailed=6
    };

    enum class ClientCode{
        enum_SentSuccess=10,
        enum_FailedOpeningClientSocket=11,
        enum_FailedClientSocketConnection=12,
        enum_FailedWritingtoClientSocket=13,
        enum_FailedReadingfromClientSocket=14
    };

    enum class ServerCode{
        enum_ReceivedSuccess=20,
        enum_FailedOpeningListenSocket=21,
        enum_FailedBindingtoListenSocket=22,
        enum_FailedAcceptingListenSocket=23,
        enum_FailedWritingtoListenSocket=24,
        enum_FailedReadingfromListenSocket=25
    };
};

#endif // ENUMS_H
rocambille
  • 15,398
  • 12
  • 50
  • 68
CybeX
  • 2,060
  • 3
  • 48
  • 115

1 Answers1

2

Your error is not on the second, but on the first parameter. From your question, I guess you have code like this:

struct ReturnCode
{
    enum class ClientCode
    {
        enum_FailedSocketConnection,
        // other values
    };
};

So you ended up with two declared types: ReturnCode and ReturnCode::ClientCode. Looking at your constructor declaration:

`ReturnObject::ReturnObject(ResultCode enum_code, QString data)`

It needs an object of type ReturnCode as first parameter, while looking at your call:

ReturnObject(ResultCode::ClientCode::enum_FailedSocketConnection, "")

You pass an object of type ReturnCode::ClientCode as first parameter.

You may change your code like this:

class ReturnObject
{
public:
    ReturnObject(ResultCode::ClientCode enum_code, QString data);

    QString getData();
    ResultCode::ClientCode getCode();

private:
    ResultCode::ClientCode e_code;
    QString data_string;

};

Once you are here. You may consider taking the enumeration out of ResultCode:

enum class ClientCode
{
    enum_FailedSocketConnection,
    // other values
};

class ReturnObject
{
public:
    ReturnObject(ClientCode enum_code, QString data);

    QString getData();
    ClientCode getCode();

private:
    ClientCode e_code;
    QString data_string;

};

This follows the Zen of Python: "Flat is better than nested". IMHO this is also true in C++.

EDIT:

From your comments, we're here on an XY problem, and your code needs to be redesign. Here is a first proposition:

#include <type_traits>

enum class ClientCode{
    // ...
    enum_FailedClientSocketConnection=12,
    // ...
};

template<typename T>
struct ReturnObject
{
    static_assert(std::is_enum<T>::value, "T should be an enum");

    const T e_code;
    const QString data_string;
};

template<typename T>
ReturnObject<T> make_return_object(T e_code, std::string data_string)
{
    return ReturnObject<T>{e_code, data_string};
}

// usage

return make_return_object(
    ClientCode::enum_FailedClientSocketConnection, ""
);

I removed the accessors getData and getCode for public const members: they are just read, and should not change for a given return object, so let them be public, with the const qualifier to prevent modification.

I used templates to represent the code, with static_assert to check the given type is an enumeration.

The drawbacks are:

  • You can pass any enumeration, not only your result codes.
  • make_return_object will return a different type for each different enumeration.
rocambille
  • 15,398
  • 12
  • 50
  • 68
  • Hell yeah ! Thanks. One question though, you are almost correct with your derived code, see my update, I have a nested enum. I need cast my `ResultCode::enum_FailedOpeningClientSocket` as a `ResultCode::ClientCode` object. How should this be done, rather which should I use, dynamic or static? – CybeX Oct 12 '16 at 14:49
  • Neither `dynamic_cast` nor `static_cast`: a nested type is not related to its "nesting" type and there can **not** be cast between them, as you could have when using inheritance. The nesting type acts here like a namespace with `private` and `protected` options. Why do you need `ResultCode`? Unless you want to pass any enum nested in `ResultCode`as argument to your functions, but I can't see the point here: if you need a `ClientCode`, you should not allow to pass anything else, and the way to do that is to declare the argument as a `ClientCode` – rocambille Oct 12 '16 at 15:16
  • infact that is exactly why I need `ResultCode`, since I will using this ReturnObject in a few different classes, I require a class that I can insert any enum from `ResultCode` and a supporting string/(char array). I just realized I do not require `ResultCode` as a `enum` but as a `struct` as you pointed out. But since I can insert any `enum` from `ResultCode`, I am required to typecast it do the appropriate `enum class`. That is what I am refering to, should this be a normal cast like `(ResultCode::ClientCode)ResultCode::ClientCode::enum_Failed...`. I am testing this now... – CybeX Oct 12 '16 at 15:23
  • 1
    That should **NOT** be a cast :) You are here in a wrong design. I will propose you an answer, but I can't today – rocambille Oct 12 '16 at 15:27
  • Thank you for the trouble, I have resorted to combining all enums into one class, for the moment. I eagerly await your proposed solution/new design, I would love to get a fresh opinion on this! – CybeX Oct 12 '16 at 21:59
  • I edited my answer with a first proposition. I guess it will be incomplete for you, but, without details on how you're using `ReturnObject`, your question is too broad. Maybe you will need a real type erasure like `variant`, or `any`. Feel free to edit your question with a complete use case – rocambille Oct 13 '16 at 08:25