【发布时间】:2020-08-27 09:20:14
【问题描述】:
代码
我有一个遵循Observer Pattern 的模板类型。
template <typename T>
class Subject {
public:
template <template<typename> typename Observer>
void AddObserver(Observer<T>& observer)
{
observers.push_back([&](const T& value) { observer.OnEvent(value); });
}
void Event(const T& value) const
{
for (auto& o : observers) {
o.OnEvent(value)
}
}
private:
std::vector<std::function<void(const T&)>> observers;
};
上面的效果很好,但前提是Observer 是模板类型。所以我可以修改模板签名并接受任何类型,不管它们是否被模板化。
template <typename Observer>
void AddObserver(Observer& observer)
{
observers.push_back([&](const T& value) { observer.OnEvent(value); });
}
问题
但是现在没有对 Subject 和 Observer 之间的类型匹配进行任何编译时检查。 (EDIT已经指出,不能保证Observer<T>在其OnEvent函数签名中实际使用T)
我想向检查Subject<**T**> 和Observer::OnEvent(const **T**&) 两种类型是否相同的函数添加一个静态转换,以防止自动类型转换。如下所示。
static_cast(std::is_same<T, **type_of_first_param**(Observer::OnEvent)>::value, "Subject/Observer type mistatch.");
我需要帮助的可能方法
如果我不能从函数签名中提取类型,也许我可以构造一个可以与之比较的函数签名?
static_cast(std::is_same<**Observer::MadeUpFunc(const T&)**, Observer::OnEvent>::value, "Subject/Observer type mistatch.");
我正在调查this QA,我很确定它可以找到我需要的答案,只是需要一些时间,也许还需要一些指导来弄清楚。
我尝试了以下方法,但得到编译时错误
typename 说明符指的是 'Observer' 中的非类型成员 'OnEvent'
static_assert(std::is_same<typename Observer::OnEvent, void (Observer::*)(const T&...)>::value, "");
我尝试过的
- 我已阅读此处的文档cppreference.com/w/cpp/types
- 我已经阅读了这里cppreference.com/w/cpp/language 的一些文档,即Functions 和Templates 下的部分
- 我读过这个drdobbs.com/cpp/extracting-function-parameter-and-return
- 我看过这些类似 QAs Extracting function argument types as a parameter pack, “unpacking” a tuple to call a matching function pointer
【问题讨论】:
-
是的,但是第一个如何确保
OnEvent有一个与T匹配的参数,只有当模板类使用其模板作为OnEvent的参数时才会出现这种情况。 -
是的,我只是想确保我理解正确,问题在第一个示例中也仍然存在。
-
你已经要求
Observer有一个函数OnEvent(OtherT value)。为什么不要求一个类型名:using EventArg = OtherT,然后使用static_assert<std::is_same_v<T, typename Observer::EventArg > >? -
关键是如果你需要
template<typename T> struct Observer { void OnEvent(T e) {}};,那么你也可以需要struct Observer {using EventArg = SomeType; void OnEvent(EventArg e) {}],你可以检查Observer::EventArg,它和你的第一个例子一样可靠。但肯定不是您要求的可靠性。这个using EventArg = SomeType;存在于std 库中的许多地方(以及其他地方),用于获取有关某些类型的类的信息(例如value_type',allocator_type,size_type, … instd::vector`)。 -
@Troyseph 在这种特殊情况下可能不是问题。我现在无法举出一个例子,但在某些情况下,您可能想要获取参数的实际类型或类的其他类型。并且定义一个类必须有一个清晰的接口,提供一个或多个
using sometype_t = its_actual_type;并相应地使用它们,这使得许多事情变得更容易和一致。
标签: c++ static-assert compile-time-type-checking