无法将std :: function移入地图

Dem*_*unt 0 c++ templates move-semantics

我有一些信号原型类

#include <map>
#include <string>
#include <functional>

template <class T>
class Signal
{
public:
    std::function<T> slot;
};
Run Code Online (Sandbox Code Playgroud)

接下来是模板单例SignalCollection类,该类自动为Signal

template <class T>
class SignalCollection
{
private:
    SignalCollection() {}
    SignalCollection(const SignalCollection&) = delete;
    SignalCollection& operator= (const SignalCollection&) = delete;
public:

    static SignalCollection& Instance()
    {
        static SignalCollection br{};
        return br;
    }

    std::map<std::string, T> signals_map;

    void add(T&& signal)
    {
        this->signals_map.insert(std::make_pair("a", std::forward<T>(signal)));
    }
};
Run Code Online (Sandbox Code Playgroud)

最后,我有一个函数可以推断SignalCollection某些类型Signal

template<class T>
auto& get_collection_for_signal(T&& t)
{
    return SignalCollection<T>::Instance();
}
Run Code Online (Sandbox Code Playgroud)

问题是,我无法将值添加到集合图。这是主要的:

void foo()
{

}
void main()
{
    Signal<void()> sgl = Signal<void()>{}; //Create signal
    sgl.slot = foo;                       //add slot

    auto& t = get_collection_for_signal(sgl); //Get collection for this signal which is SignalCollection<Signal<void()>>

    t.add(sgl); //error 1
    t.signals_map["a"] = sgl; //error 2
}
Run Code Online (Sandbox Code Playgroud)

Nat*_*ica 6

这里的问题是

template<class T>
auto& get_collection_for_signal(T&& t)
{
    return SignalCollection<T>::Instance();
}
Run Code Online (Sandbox Code Playgroud)

当你这样称呼它时

auto& t = get_collection_for_signal(sgl);
Run Code Online (Sandbox Code Playgroud)

T推导为Signal<void()>&,这意味着您返回的SignalCollection<Signal<void()>&>不是您想要的。您需要做的是从类型中删除引用。您可以使用

template<class T>
auto& get_collection_for_signal(T&&)
{
    return SignalCollection<std::remove_cv_t<std::remove_reference_t<T>>>::Instance();
}
Run Code Online (Sandbox Code Playgroud)

从中删除了cv资格和参考T(C ++ 20给了我们,std::remove_cvref因此可以使用单个帮助程序完成)。

您也可以通过以下方式获得相同的行为

template<class T>
auto& get_collection_for_signal(T)
{
    return SignalCollection<T>::Instance();
}
Run Code Online (Sandbox Code Playgroud)

由于顶级简历的资格被剥夺了,而且永远不会推论出参考,因此这涉及到很多打字工作,并且给您相同的行为。


您的功能也有问题add

void add(T&& signal)
{
    this->signals_map.insert(std::make_pair("a", std::forward<T>(signal)));
}
Run Code Online (Sandbox Code Playgroud)

不使用转发引用,因为它T是类类型的一部分。您需要使其具有自己的模板才能具有转发参考。您可以通过将其更改为

template<typename U>
void add(U&& signal)
{
    this->signals_map.insert(std::make_pair("a", std::forward<U>(signal)));
}
Run Code Online (Sandbox Code Playgroud)

最后

void main()
Run Code Online (Sandbox Code Playgroud)

总是错的。 main()被要求返回一个int。通读main()在C和C ++中应该返回什么?想要查询更多的信息。