1

さまざまなタイプのデータを送信するために必要ないくつかの反復機能のテンプレート クラスを作成しようとしています。ただし、私の問題 (私が思う) は、実際にはboost::signals2::signal::connect()を利用しているInterfacePublisher::addSubscription()関数にあります。

派生クラスがそれらをオーバーライドしていても、接続関数が基本クラスの場所を取得しているようです。これには修正が加えられると確信していますが、今は長い間それで立ち往生しています。

以下にコードを貼り付けます。アイデアは、テンプレートを介してクラス名をハードコーディングせずにStringPublisherからStringSubscriberに文字列を渡すことです。

#include <string>
#include <iostream>

#include <boost/lambda/lambda.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/signals2/signal_base.hpp>
#include <boost/signals2/slot.hpp>
#include <boost/signals2/slot_base.hpp>

template <class T>
class InterfaceSubscriber
{
public:
    InterfaceSubscriber(const std::string& name)
        : mName         (name) {}

    virtual void onData (const std::string&   source, T& data)
    {
        std::cout << "InterfaceSubscriber::onData::BASE SHOULD BE IGNORED\n";
    }
protected:
    const std::string mName;
};




template <class T>
class InterfacePublisher
{
public:
    InterfacePublisher(const std::string& publisherName)
        : mPublisherName         (publisherName)
    {
    }

    void publish(T& data)
    {
        mSignalArgs(mPublisherName, data);
    }

    void addSubscription (InterfaceSubscriber<T>* subsc)
    {
        // The section where I think problem is. There is where the solution should be
        mSignalArgs.connect( std::bind (InterfaceSubscriber<T>::onData , *subsc, std::placeholders::_1, std::placeholders::_2) );
    }

protected:
    boost::signals2::signal<void (const std::string& publisherName, T& data)> mSignalArgs;
    const std::string mPublisherName;
};

class StringSubscriber : public InterfaceSubscriber<std::string>
{
public:
    StringSubscriber (const std::string& subscName) : InterfaceSubscriber(subscName) {}
    void onData (const std::string&   source, std::string&        data) override
    {
        std::cout << mName << ":[" << source << "]Received string of value: " << data << std::endl;
    }
};


class StringPublisher : public InterfacePublisher<std::string>
{
public:
    StringPublisher (const std::string& name) : InterfacePublisher(name) {}
};


int main()
{
    StringSubscriber subscriber1("String_Subscriber_1");
    StringSubscriber subscriber2("String_Subscriber_2");
    StringPublisher publisher("Publisher_Of_String");
    publisher.addSubscription(&subscriber1);
    publisher.addSubscription(&subscriber2);
    std::string str = "Hello World";

    // This should lead to StringSubscriber::onData being called, but instead ends up calling InterfaceSubscriber<T>::onData
    publisher.publish(str);

}
4

1 に答える 1

0

StringSubscriberstd::bindファンクタの構築中にスライスされ、に提供されたオブジェクトの実行時型ではなく のInterfaceSubscriber<T>::onData()実行時型を持つオブジェクトで実行されます。InterfaceSubscriber<T>InterfacePublisher<T>::addSubscription()

void addSubscription(InterfaceSubscriber<T>* subsc)
{
  mSignalArgs.connect(std::bind(&InterfaceSubscriber<T>::onData, 
                                *subsc, ...);
                             // ^~~ sliced
}

これを解決するには、ポインターを直接渡すか、std::refオブジェクトをインスタンスとして渡します。

void addSubscription(InterfaceSubscriber<T>* subsc)
{
  mSignalArgs.connect(std::bind(&InterfaceSubscriber<T>::onData,
                                subsc, ...);
                             // ^~~ pointer
}

また

void addSubscription(InterfaceSubscriber<T>* subsc)
{
  mSignalArgs.connect(std::bind(&InterfaceSubscriber<T>::onData, 
                                std::ref(*subsc), ...);
                             // ^~~ reference
}
于 2013-08-22T17:36:32.630 に答える