3

I am trying to run print() and print(char ch) methods on different threads with singleton instance .

Can any body help me out why I am getting errors:-

error C3867: 'Singleton::print': function call missing argument list; use '&Singleton::print' to create a pointer to member

error C3867: 'Singleton::print': function call missing argument list; use '&Singleton::print' to create a pointer to member

error C2661: 'std::thread::thread' : no overloaded function takes 2 arguments

Also help me in correcting out the following code for me.


class Singleton
{
private:
    Singleton()
    {}
    static Singleton* singletonInstance;
public:
    static Singleton* getSingletonInstance();
    void print()
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        for (int i = 0; i < 100000; i++)
        {
            cout<<i<<endl;
        }
    }
    void print(char ch)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        for (int i = 0; i < 100000; i++)
        {
            cout<<ch<<" "<<i<<endl;
        }
    }
};
Singleton* Singleton::singletonInstance = nullptr;
Singleton* Singleton::getSingletonInstance()
{
    if(!singletonInstance)
        singletonInstance=new Singleton();

    return singletonInstance;
}

int main()
{
    std::thread t1(Singleton::getSingletonInstance()->print);
    std::thread t2(Singleton::getSingletonInstance()->print,'T');
    t1.join();
    t2.join();
    return 0;
}
AnkitG
  • 53
  • 9
  • Step 1: *Don't* use the singleton anti-pattern. It *will* come back and bite you in the ass. – Jesper Juhl Sep 18 '17 at 17:11
  • 3
    You should be using [Meyers' singleton](https://stackoverflow.com/questions/17712001/how-is-meyers-implementation-of-a-singleton-actually-a-singleton) instead. – Rakete1111 Sep 18 '17 at 17:13
  • 1
    `object.print` and equivalently `p->print` aren't valid C++. This has nothing to do with threads, you're just not passing a proper callable object. As the error says, you can create a pointer-to-member, though it won't have an object bound to it, you'd have to pass it separately. There's also the option of a lambda, which is probably easier given the overloading. – chris Sep 18 '17 at 17:15

2 Answers2

6

The posted Code have tow problems:

1- the manner you are passing the function pointer to the threads is wrong:

std::thread t1(Singleton::getSingletonInstance()->print);

and the compiler is complaining and giving you a hint how do you have to pass the function pointer to the thread. it says: use '&Singleton::print' to create a pointer to member

Also step1 you have to pass your function pointer in the following manner:

std::thread t1(&Singleton::print);

Step2: setting the object of the Sigleton class, the function pointer belong to.

std::thread t1(&Singleton::print, Singleton::getSingletonInstance());

But that will function only if you haven't overloaded the function print, because the compiler can not find out, which print do you willing to call.

Also now we comes to second problem: how to solve the problem of overloaded functions?

you have tow possibilities:

1- you tell the compiler with help of casting which function you want to call:

int main()
{
    using print1 = void (Singleton::*)();
    using print2 = void (Singleton::*)(char);
    std::thread t1(print1(&Singleton::print), Singleton::getSingletonInstance());
    std::thread t2(print2(&Singleton::print), Singleton::getSingletonInstance(), 'T');
    t1.join();
    t2.join();
    return 0;
}

2- you use lambda functions and call the function directly:

int main()
{
    auto *s = Singleton::getSingletonInstance();
    std::thread t1([&s](){s->print();});
    std::thread t2([&s]() {s->print('T');});
    t1.join();
    t2.join();
    return 0;
}

The second one is smarter and easier to understand

Mauri
  • 1,185
  • 1
  • 13
  • 21
3

First you are calling the functions wrong in your thread. You need to pass the address of the member function print followed by the pointer to the singleton - then the parameter (if any).

std::thread(&Singleton::print, Singleton::getSingletonInstance());

Second, because you are calling an overloaded function you need to cast the address of the member function to the correct overloaded type.

// call the char version
std::thread(static_cast<void(Singleton::*)(char)>(&Singleton::print), Singleton::getSingletonInstance(), 'T');

Something like this:

class Singleton
{
private:
    Singleton()
    {}
    static Singleton* singletonInstance;
public:
    static Singleton* getSingletonInstance();
    void print()
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        for (int i = 0; i < 100000; i++)
        {
            cout<<i<<endl;
        }
    }
    void print(char ch)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
        for (int i = 0; i < 100000; i++)
        {
            cout<<ch<<" "<<i<<endl;
        }
    }
};
Singleton* Singleton::singletonInstance = nullptr;
Singleton* Singleton::getSingletonInstance()
{
    if(!singletonInstance)
        singletonInstance=new Singleton();

    return singletonInstance;
}

int main()
{
    std::thread t1(static_cast<void(Singleton::*)()>(&Singleton::print), Singleton::getSingletonInstance());
    std::thread t2(static_cast<void(Singleton::*)(char)>(&Singleton::print), Singleton::getSingletonInstance(), 'T');
    t1.join();
    t2.join();
    return 0;
}

Alternatively you can call your singleton's functions through a lambda expression which actually makes things a lot easier:

std::thread t1([]{Singleton::getSingletonInstance()->print();});
std::thread t2([]{Singleton::getSingletonInstance()->print('T');});

See Lambda Expressions.

Galik
  • 47,303
  • 4
  • 80
  • 117