Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function overloading with std::function argument: why is the const method never called?

#include <functional>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class A
{
    public:
    void doStuff(function<void (const string *)> func) const
    {
        cout << "Const method called" << endl;
        for(const auto& i_string : m_vec)
            func(i_string);
    }

    void doStuff(function<void (string *)> func)
    {
        cout << "Non-const method called" << endl;
        doStuff([&func](const string *str)
        {
            auto mutableString = const_cast<string *>(str);
            func(mutableString);
        });
    }

private:
    vector<string *> m_vec;
};

int main()
{
    auto a = A{};

    a.doStuff([](string *str){
        *str = "I modified this string";
    });
}

In this example, the const method is never called. If the code looks weird, here's what I'm trying to do:

Instead of a getter method, I let clients iterate objects by passing a function. To enable both const and non-const access, I want to provide const and non-const overloads. Further, to avoid copy & paste, I want to implement the non-const method in terms of the const method: the const method in my code is actually more complicated than the one I use here.

Now, my questions is this: If you run this code, it will recursively call the non-const function until the stack overflows. I don't understand why the line doStuff([&func](const string *str) in the non-const method calls itself and not the const method.

like image 690
Leander Avatar asked Jan 08 '23 01:01

Leander


2 Answers

The non-const method is declared as accepting function that can be called with string * argument. The provided function accepts const string *. string * is implicitely convertible to const string*. Therefore the function with const string * is acceptable argument for the non-const method and the non-const method is selected because this is non-const as well.

Use const_cast on this to use the const method:

const_cast<const A*>(this)->doStuff(…);
like image 140
StenSoft Avatar answered Jan 29 '23 00:01

StenSoft


The const overload is only called when an instance of the A class is const. This is the case because of the const at the end of the declaration:

void doStuff(function<void (const string *)> func) const //This const at the end causes
                                                         //The member function to only be
                                                         //called when `a` is const

The const-qualifier at the end applies to the this object, not to the parameters. Removing the const will cause ambiguity, so use StenSoft's way to get it to work.

like image 43
JKor Avatar answered Jan 28 '23 23:01

JKor