user6245072 user6245072 - 1 month ago 5
C++ Question

Operator overloading based on passed int?

I am trying to implement my own programing language in C++.

When an error occours in my language (for example, during lexical analysis), an exception is thrown to be catched by the main function which then prints its message.

The exception can be of different types: either

, or
and so on, all based on the
class so that they can all be catched even being of different types.

Each sub class of errors anyway can generate different types of error, each one requiring different informations on what was happening when the error was thrown to construct its error message.

To solve this problem, I accounted for this solution:

//Error contains a public "message" attribute of type std::string, and a constructor to initialize that string

class SyntaxError: public Error {
SyntaxError(int code, void* infos[]) {
Error("SintaxError: ");
switch (code) {
//each sub error has its own code and based on that the function assumes the pointers to the objects needed to construct the error message are stored in the infos array
case 1: //Unfinished string
//it assumes the line at which the error is thrown is stored in the first position of the passed array
message += "Unfinished string (at line " + std::to_string(*((int*) infos[0])) + ").";
case 2: //Malformed number
... //other errors, each one assuming in the infos array are stored pointers to different types of objects

This however requires a great setup when you want to throw the error (because you must estabilish what type of error you want to throw and based on that create an array of pointers to the informations required) and it's also pretty messy in the constructor itself: I can't even name the objects required because I can't declare them in the switch statement and I should declare all of them at the start of the function.

So I tought to another solution: overloading the constructor with the objects needed, so that when I want to throw a unfinished string error I just have to pass an
, the line, and when I want to throw a malformed number error I have to pass an
and a
(the malformed number), and so on.

The point is, there will be errors requiring the same number, and types, of informations, like, a invalid escape sequence used in string error, for an example, would require an
(the line), and a
(the escape sequence used), just like the malformed number overload, and I don't know how to differentiate them.

So, is there a way to tell the compiler which function between different functions with the same parameter list to call based on an integer I pass to the function?


Short answer

The technique you are looking for is named tag dispatching.

Long answer

Using ints (and std::integral_constants to dispatch the request?) is somehow hard to read, I'd rather define an enum class and use a template method.

As an example:

enum class Tag { FOO, BAR };

Then you have mainly two choices:

  • Template method and full specializations:

    void myMethod(int arg1, char arg2);
    void myMethod<Tag::FOO>(int arg1, char arg2) {}
    void myMethod<Tag::BAR>(int arg1, char arg2) {}

    To be invoked as:

    myMethod<Tag::FOO>(42, 'c');
  • Tag dispatching:

    void myMethod(tag<Tag::FOO>, int arg1, char arg2) {}
    void myMethod(tag<Tag::BAR>, int arg1, char arg2) {}

    To be invoked as:

    myMethod(tag<FOO>{}, 42, 'c');

    In this case, you have to define the tag struct somewhere. As an example:

    struct tag {};

Note: As mentioned in the comments, both the solutions work well also with a plain old enum.