【问题标题】:C++ Class template with functions from inherit parents具有来自继承父级的函数的 C++ 类模板
【发布时间】:2020-12-14 04:52:21
【问题描述】:

让我们假设这个类使用 C++14(和原始的 QtRO 系统)。 https://pastebin.com/EVT4XJiz

#include <iostream>
#include <functional>
#include <memory>
 
class QTRO_1Source {
public:
    void hvEnabledChanged(bool) {};
    virtual bool hvEnabled() const = 0;
};
 
class QTRO_1SimpleSource : public QTRO_1Source {
public:
    bool hvEnabled() const override { return false; }
};
 
class QTRO_1 : public QTRO_1SimpleSource {
public:
    void write_hvEnabled(bool/*enabled*/) { }
};
 
 
template<typename ReplicaType, typename ValueType>
class ProxyProperty
{
public:
    using ReadFuncPtr = ValueType (ReplicaType::*)() const;
    using WriteFuncPtr = void (ReplicaType::*)(ValueType);
    using ChangeSigFuncPtr = void (ReplicaType::*)(ValueType);
    using UpdateHandlerFunctor = std::function<void(ValueType value)>;
    ProxyProperty(ReplicaType *replica,
                  ReadFuncPtr readFunc,
                  WriteFuncPtr writeFunc,
                  ChangeSigFuncPtr changeSignal,
                  UpdateHandlerFunctor updateHandler)
    {
        m_replica = replica;
        m_readFunc = readFunc;
        m_writeFunc = writeFunc;
        m_changeSignal = changeSignal;
        m_updateHandler = updateHandler;
    }
    template<typename T, typename HandlerT>
    void write(T value, HandlerT handler) {
        (m_replica->*m_writeFunc)(value);
    }
private:
    ReplicaType *m_replica;
    ReadFuncPtr m_readFunc;
    WriteFuncPtr m_writeFunc;
    ChangeSigFuncPtr m_changeSignal;
    UpdateHandlerFunctor m_updateHandler;
    int m_timeout{3000};
};
 
template<typename ReplicaType, typename ValueType, typename UpHandlerT>
auto createProxyProperty(ReplicaType *replica,
                         ValueType (ReplicaType::*readFunc)() const,
                         void (ReplicaType::*writeFunc)(ValueType),
                         void (ReplicaType::*changeSignal)(ValueType),
                         UpHandlerT upHandler)
{
    return std::make_unique<ProxyProperty<ReplicaType,ValueType> >(replica, readFunc, writeFunc, changeSignal, upHandler);
}
 
int main(int argc, char *argv[]){
    QTRO_1 model;
//    static auto p = createProxyProperty<QTRO_1, bool>(
    static auto p = createProxyProperty(
                &model,
                &QTRO_1::hvEnabled,
                &QTRO_1::write_hvEnabled,
                &QTRO_1::hvEnabledChanged,
        [](auto val) { std::cout<< "COSTAM"; }
    );
}

现在,当我将它与第一行一起使用时(同时给出两种类型) - 它可以工作。当我在编译器上移动类型推导时 - 我收到此错误错误。

错误:没有匹配函数调用‘createProxyProperty(QTRO_1*, bool (QTRO_1SimpleSource::)() const, void (QTRO_1::)(bool), void (QTRO_1Source::*)(bool), main(int, char**)::)’ 76 | );

是的,所有 3 个方法都来自继承树中的不同类(QTRO_1 来自 QTRO_1SimpleSource 来自 QTRO_1Source)。我可以 - 当然 - 将这些方法包装在 std::function 中。
我想让编译器为我推断类型。 怎么做?

PS:添加了最少的复制代码。

【问题讨论】:

标签: c++ templates inheritance


【解决方案1】:

ReplicaType 由 4 个不同的参数推导出来,推导的结果是相互矛盾的。查看编译器输出:

注意:候选模板被忽略:推断参数“ReplicaType”的冲突类型(“QTRO_1”与“QTRO_1SimpleSource”)

您可以通过在 2-4 个函数参数中为类类型使用 3 个附加模板参数来解决此问题:

template<typename ReplicaType, typename ValueType, typename UpHandlerT,
         class C1, class C2, class C3>
auto createProxyProperty(ReplicaType *replica,
                         ValueType (C1::*readFunc)() const,
                         void (C2::*writeFunc)(ValueType),
                         void (C3::*changeSignal)(ValueType),
                         UpHandlerT upHandler)
{
    return std::make_unique<ProxyProperty<ReplicaType,ValueType> >(replica, readFunc, writeFunc, changeSignal, upHandler);
}

查看完整示例here

【讨论】:

  • 我得出了类似的结论。然而,有那么一瞬间,我认为可能还有其他更好、更安全的解决方案(比如 dynamic_cast,但在编译时)。可以保护并确认所有 3 种方法都来自同一个对象的东西。
  • 多部分注释 [1] 方法不属于对象,而是属于类。您将指针传递给 Class 成员函数,这里没有对象。您通过第一个函数参数传递类对象。此时对象(通过第一个函数参数传递)和指向类成员的指针根本不相关(不受约束)。
  • [2] 此时ValueType (C1::*readFunc)() constValueType (ReplicaType::*readFunc)() const 类型甚至可能不兼容。可能你关心这个细节。但是在实例化ProxyProperty(在函数体中)时,如果类型不兼容,则会出现编译时错误。该程序不会以错误的类型编译。但是如果你想更明确一点,你可以添加一些static_asserts(is_base_ofis_convertible),见godbolt.org/z/KWMhz6
  • 广告 [1] - 是的。广告 [2] - 谢谢,在 createProxyProperty 中我可以添加此检查,并且应该在用户错误的情况下进行有意义的诊断。
猜你喜欢
  • 1970-01-01
  • 2020-11-16
  • 2014-06-04
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多