无法将 std::function 移动到地图中
Cannot move std::function into map
我有一些 Signal 原型 class
#include <map>
#include <string>
#include <functional>
template <class T>
class Signal
{
public:
std::function<T> slot;
};
接下来是模板单例 SignalCollection
class,它会自动为 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)));
}
};
最后我有一个函数可以推导某些 Signal
的 SignalCollection
类型
template<class T>
auto& get_collection_for_signal(T&& t)
{
return SignalCollection<T>::Instance();
}
问题是,我无法将值添加到集合映射。这是主要的:
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
}
T&&
如果T
不推导就不是转发引用,反之
template<class T>
auto& get_collection_for_signal(T&& t)
T
在您的示例中被推断为对 Signal<void()>
的引用:
auto& t = get_collection_for_signal(sgl);
所以它 returns:
return SignalCollection<T>::Instance();
即:
SignalCollection<Signal<void()>&>::Instance()
这是胡说八道。
复习转发引用和 l/rvalue 引用。在您的代码中每次使用它都是错误的。
明智的设计,你有无用的类型 -- Signal<T>
写的是一个 std 函数,带有什么都不做的包袱 -- 全局单例,类型推导创建全局状态。
我明白你想做什么,但这就像想用稻草做一辆消防车一样。
这里的问题是
template<class T>
auto& get_collection_for_signal(T&& t)
{
return SignalCollection<T>::Instance();
}
当你这样称呼它时
auto& t = get_collection_for_signal(sgl);
T
被推断为 Signal<void()>&
,这意味着你 return 一个 SignalCollection<Signal<void()>&>
这不是你想要的。您需要做的是从类型中删除引用。您可以使用
template<class T>
auto& get_collection_for_signal(T&&)
{
return SignalCollection<std::remove_cv_t<std::remove_reference_t<T>>>::Instance();
}
删除了 cv 资格和 T
的引用(C++20 给了我们 std::remove_cvref
所以它可以用一个助手来完成).
您也可以使用
获得相同的行为
template<class T>
auto& get_collection_for_signal(T)
{
return SignalCollection<T>::Instance();
}
这涉及更少的输入,并为您提供相同的行为,因为顶级简历资格被删除并且它永远不会推断出参考。
您的 add
功能也有问题。
void add(T&& signal)
{
this->signals_map.insert(std::make_pair("a", std::forward<T>(signal)));
}
没有使用转发引用,因为 T
是 class 类型的一部分。您需要使其成为自己的模板才能具有转发参考。您可以将其更改为
template<typename U>
void add(U&& signal)
{
this->signals_map.insert(std::make_pair("a", std::forward<U>(signal)));
}
最后
void main()
总是错误。 main()
被授权给 return 和 int
。通读 What should main() return in C and C++? 了解更多信息。
其他答案都很好地解释了错误,但我会推荐其他解决方案来解决问题。
我看到在您的代码中您实际上不需要转发引用。您仅将其用于扣除。在这种情况下,您可以通过 T const&
来进行论证,它总是会在没有引用的情况下推导出 T
。
template<class T>
auto& get_collection_for_signal(T const& t)
{
return SignalCollection<T>::Instance();
}
我有一些 Signal 原型 class
#include <map>
#include <string>
#include <functional>
template <class T>
class Signal
{
public:
std::function<T> slot;
};
接下来是模板单例 SignalCollection
class,它会自动为 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)));
}
};
最后我有一个函数可以推导某些 Signal
SignalCollection
类型
template<class T>
auto& get_collection_for_signal(T&& t)
{
return SignalCollection<T>::Instance();
}
问题是,我无法将值添加到集合映射。这是主要的:
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
}
T&&
如果T
不推导就不是转发引用,反之
template<class T>
auto& get_collection_for_signal(T&& t)
T
在您的示例中被推断为对 Signal<void()>
的引用:
auto& t = get_collection_for_signal(sgl);
所以它 returns:
return SignalCollection<T>::Instance();
即:
SignalCollection<Signal<void()>&>::Instance()
这是胡说八道。
复习转发引用和 l/rvalue 引用。在您的代码中每次使用它都是错误的。
明智的设计,你有无用的类型 -- Signal<T>
写的是一个 std 函数,带有什么都不做的包袱 -- 全局单例,类型推导创建全局状态。
我明白你想做什么,但这就像想用稻草做一辆消防车一样。
这里的问题是
template<class T>
auto& get_collection_for_signal(T&& t)
{
return SignalCollection<T>::Instance();
}
当你这样称呼它时
auto& t = get_collection_for_signal(sgl);
T
被推断为 Signal<void()>&
,这意味着你 return 一个 SignalCollection<Signal<void()>&>
这不是你想要的。您需要做的是从类型中删除引用。您可以使用
template<class T>
auto& get_collection_for_signal(T&&)
{
return SignalCollection<std::remove_cv_t<std::remove_reference_t<T>>>::Instance();
}
删除了 cv 资格和 T
的引用(C++20 给了我们 std::remove_cvref
所以它可以用一个助手来完成).
您也可以使用
获得相同的行为template<class T>
auto& get_collection_for_signal(T)
{
return SignalCollection<T>::Instance();
}
这涉及更少的输入,并为您提供相同的行为,因为顶级简历资格被删除并且它永远不会推断出参考。
您的 add
功能也有问题。
void add(T&& signal)
{
this->signals_map.insert(std::make_pair("a", std::forward<T>(signal)));
}
没有使用转发引用,因为 T
是 class 类型的一部分。您需要使其成为自己的模板才能具有转发参考。您可以将其更改为
template<typename U>
void add(U&& signal)
{
this->signals_map.insert(std::make_pair("a", std::forward<U>(signal)));
}
最后
void main()
总是错误。 main()
被授权给 return 和 int
。通读 What should main() return in C and C++? 了解更多信息。
其他答案都很好地解释了错误,但我会推荐其他解决方案来解决问题。
我看到在您的代码中您实际上不需要转发引用。您仅将其用于扣除。在这种情况下,您可以通过 T const&
来进行论证,它总是会在没有引用的情况下推导出 T
。
template<class T>
auto& get_collection_for_signal(T const& t)
{
return SignalCollection<T>::Instance();
}