微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

函数参数的 C++ 类型擦除

如何解决函数参数的 C++ 类型擦除

所以在 Java 中我们有泛型,我希望在 C++ 中实现类似于以下内容

public interface ListenerIF <T> {
    public void onChange(T eventData);
}

...

public static void main(String[] args) {
    List<ListenerIF<String>> foo = ...;
    List<ListenerIF<Integer>> bar = ...;
    foo.add((strUpdate) -> {/*some string operation*/});
    bar.add((intUpdate) -> {/*some math*/});
    foo.forEach((listener) -> listener.onChange("some change"));
    bar.forEach((listener) -> listener.onChange(123));
}

但是由于 C++ 模板从根本上是不同的(并且需要预先实现所有实现),我试图了解如何使用类型擦除在 C++ 中完成类似的事情(并且由于 JVM 是用 C++ 编写的,我很确定这是可能的,只是逃避我)。

我可以在 ListenerIF 方面获得我想要的类型擦除,但我不知道如何使 T 函数的类型为动态 ListenerIF::onChange(T)。这就是我让 ListenerIF 工作的目的(没有 T 是动态的,这里就像 std::string):

class ListenerIF {
  public:
    //how do I get the parameter to this function to be dynamic?
    virtual void onChange(std::string) = 0;
};

template<typename LISTENER>
class Listener: public ListenerIF {
  public:
    //how do I get the parameter to this function to be dynamic?
    void onChange(std::string update) {
      l.onChange(update);
  private:
    LISTENER l;
};

class Foo {
  public:
    //how do I get the parameter to this function to be dynamic?
    void onChange(std::string);
};
class Bar {
  public:
    //how do I get the parameter to this function to be dynamic?
    void onChange(std::string);
};

void Foo::onChange(std::string update){}
void Bar::onChange(std::string update){}

int main() {
  std::vector<ListenerIF *> listeners;
  listeners.push_back(new Listener<Foo>());
  listeners.push_back(new Listener<Bar>());
  for(std::vector<ListenerIF *>::iterator listenersItr = listeners.begin(); listenersItr < listeners.end(); listenersItr++){
    (*listenersItr)->onChange("some string update");
}

如果我只想将 'onChange' 仅用于字符串,这一切都很好,但是如果我想要一个完全不同的 'onChange' 类型为 int、float 或其他一些对象类型,那么这会崩溃.

我是否只是不理解我遗漏的一些简单内容

解决方法

Java 版本 (ListenerIF<T>) 中未擦除参数。

等效的 C++ 也会保留参数:

template <typename T> // <- need a template parameter
class listener_interface {
public:
    virtual void on_change(const T& data) = 0;
};
,

您需要将模板应用到 ListenerIF 本身,就像 Java 代码一样,例如:

#include <vector>
#include <memory>

template <typename T>
class ListenerIF {
public:
    virtual ~ListenerIF() {};
    virtual void onChange(const T &eventData) = 0;
};

template <typename T>
using listenerIF_ptr = std::unique_ptr<ListenerIF<T>>;

...

class FooListener : public ListenerIF<std::string> {
public:
    void onChange(const std::string &eventData) override {
        /* some string operation */
    }
};

class BarListener : public ListenerIF<int> {
public:
    void onChange(const int &eventData) override {
        /* some math */
    }
};

...

int main() {
    std::vector<ListenerIF_ptr<std::string>> foo;
    std::vector<ListenerIF_ptr<int>> bar;

    foo.push_back(std::make_unique<FooListener>());
    bar.push_back(std::make_unique<BarListener>());

    for(auto &listener : foo) { listener->onChange("some change"); }
    for(auto &listener : bar) { listener->onChange(123); }
}

Demo

但是,在这种情况下,我建议将 std::function(甚至是普通函数指针)与 lambdas 一起使用,而不是使用多态接口类型,例如:

#include <vector>
#include <functional>

template <typename T>
using listenerIF = std::function<void(const T&)>;
// or: listenerIF = void(*)(const T&);

int main() {
    std::vector<listenerIF<std::string>> foo;
    std::vector<listenerIF<int>> bar;

    foo.push_back(
        [](const std::string &eventData){
            /* some string operation */
        }
    );
    bar.push_back(
        [](const int &eventData) {
            /* some math */
        }
    );

    for(auto &listener : foo) { listener("some change"); }
    for(auto &listener : bar) { listener(123); }
}

Demo

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。