Search code examples
c++classconstantsmpiinitializer

Initializing C++ const members with data from function (MPI_comm_size/rank)


I'm creating a class at the moment to wrap some MPI communciation functions, which I construct with a particular MPI communicator. I'd like the class to have the rank and communicator size available as constant member variables. Unfortunately, these are only available by passing a pointer to an int into a C function.

class Comm {
public:
    const int rank;
    const int size;
    Comm(MPI_Comm);
};

Comm::Comm(MPI_Comm c) {
    MPI_Comm_rank(c, &rank); //error: rank is const
}

Two approaches spring to mind to get around this:

1) Inherit from some other class that gets the values

class Initializer {
protected:
    int hiddenSize;
    int hiddenRank;
public:
    Initializer(MPI_Comm);
}

class Comm : private Initializer {
public:
    const int size;
    const int rank;
    Comm(MPI_Comm);
}

Initializer::Initializer(MPI_Comm c) {
    MPI_Comm_rank(c, &hiddenRank);
    MPI_Comm_size(c, &hiddenSize);
}

Comm::Comm(MPI_Comm c) : Initializer(c), rank(hiddenRank), size(hiddenSize) {}

2) Make the members accessible only by function calls

class Comm {
private:
    int rank;
    int size;
public:
    Comm(MPI_Comm);
    int getRank();
    int getSize();
};

Comm::Comm(MPI_Comm c) {
    MPI_Comm_rank(c, &rank);
    MPI_Comm_size(c, &size);
}

int Comm::getRank() {
    return rank;
}

int Comm::getSize() {
    return size;
}

I wonder if I've missed a more elegant way of approaching this, and what the relative merits and disadvantages are of the two.


Solution

  • You could write wrapper functions to initialise const members in the initialiser list.

    class Comm {
    public:
        const int rank;
        const int size;
        Comm(MPI_Comm) : rank(get_rank(c)), size(get_size(c)) {}
    
    private:
        static int get_rank(MPI_Comm c) {
            int rank;
            MPI_Comm_rank(c, &rank);
            return rank;
        }
        // and likewise for size
    };
    

    This would be tidier than bloating the object with "hidden" members used only during construction; and might be better than private variables with accessors since you can enforce const-correctness within the class's members.