Search code examples
c++constantsparameter-passingfunction-signature

When is it safe to leave out a const from a function's parametrization?


Many times I write C++ functions I seem to use many more const modifiers than other folks.

For example, I write Excel .xlsx files and I use LibXL library for this, and the documentation mentions a function like this:

bool writeNum(int row, int col, double value, Format* format = 0)

I happened to inherit this function and my signature looks like this:

bool XLAPIENTRY writeNum(const int row, const int col, const double value, IFormatT<wchar_t> * format = 0);

Note the const ints for the row and the column.

Question: is it safe to leave out const for ints? (It's obviuos that for pointers, leaving out const for pointers is dangerous, but doing something a local copy of an int is not that dangerous). Note that the original header containing writeNum function doesn't mention const-ing the ints, too. Why is here the const modifiers left out?


Solution

  • In declaration (as opposed to definition), the top-level1 const on a parameter has no effect. Arguably, it's an implementation detail of the function, that shouldn't appear in the declaration (it adds clutter, yet doesn't provide any new information for the caller).

    Note that const int x and int *const x are top-level const, while const int * and const int & are not, so the latter can't have its const removed.

    In definition, you can include the const if it helps you as the implementer of the function (so you don't change the parameter accidentally).


    1 "Top-level const" means "actually const", as opposed to e.g. merely being a pointer to const. You can check this property with std::is_const_v.

    E.g.:

    • std::is_const_v<const int> == true (const integer)
    • std::is_const_v<const int *> == false (non-const pointer to const integer)
    • std::is_const_v<int *const> == true (const pointer to non-const integer)
    • std::is_const_v<const int **> == false (non-const pointer to non-const pointer to const integer)
    • std::is_const_v<int *const *> == false (non-const pointer to const pointer to non-const integer)
    • std::is_const_v<int **const> == true (const pointer to non-const pointer to non-const integer)