【问题标题】:C++ template instance as function parameter and lambda binary predicateC++ 模板实例作为函数参数和 lambda 二进制谓词
【发布时间】:2020-05-31 14:20:59
【问题描述】:

我正在修复我的项目中的一些声纳云问题。一个抱怨是我读取和反序列化我的应用程序设置的功能。基本上一个函数中有 50 个左右的块:

if (!m_logLevel.deserializeFromSettings(settings, HGGW_KEY_LOGLEVEL) || m_logLevel.value() <= 0 || m_logLevel.value() > 4)
    {
        m_logLevel.update(HGGW_DEFAULT_LOGLEVEL, 0);
        m_logLevel.serializeToQSettings(settings, HGGW_KEY_LOGLEVEL);
    }

成员是模板类的实例:

template <typename T>
class AwsProperty
{
public:
    AwsProperty(T value, qint64 timestamp) : m_timestamp(timestamp), m_data(value){}
    //other stuff, not important
}
//example:
AwsProperty<int> m_property;

我试图设计这个功能:

template <typename X>
    void readAWSSettingOrPopulateDefault(AwsProperty<X> property, QString key, X default_val, QSettings settings, bool (*predicate)(X)){
        if(!property.deserializeFromSettings(settings,key) || predicate(property.value())){
            property.update(default_val, 0);
            property.serializeToQSettings(settings, key);
        }
    }

尝试调用它:

    this->readAWSSettingOrPopulateDefault(m_logLevel, HGGW_KEY_LOGLEVEL, HGGW_DEFAULT_LOGLEVEL, settings, [](int val){return val <= 0 || val > 4;});

产生此错误:

XXXXconfig.cpp:275: error: no matching function for call to ‘LocalConfig::readAWSSettingOrPopulateDefault(HGGWAwsPropertyInt32&, const QString&, const int&, QSettings&, LocalConfig::init(QString)::<lambda(int)>)’
     this->readAWSSettingOrPopulateDefault(m_logLevel, HGGW_KEY_LOGLEVEL, HGGW_DEFAULT_LOGLEVEL, settings, [](int val){return val <= 0 || val > 4;});
XXXXconfig.cpp:275: note:   mismatched types ‘bool (*)(X)’ and ‘LocalConfig::init(QString)::<lambda(int)>’
     this->readAWSSettingOrPopulateDefault(m_logLevel, HGGW_KEY_LOGLEVEL, HGGW_DEFAULT_LOGLEVEL, settings, [](int val){return val <= 0 || val > 4;});
                                                                                                                                                   ^                                                                                                                                                   ^
                                                                                                                                                   XXXXconfig.cpp:275: note:   mismatched types ‘bool (*)(X)’ and ‘LocalConfig::init(QString)::<lambda(int)>’
                                                                                                                                                   ^

【问题讨论】:

  • 如何使用模板类作为函数参数和二进制 lambda 谓词?
  • @JeJo 我将解决它的尝试添加到顶部

标签: c++ templates lambda


【解决方案1】:

您的代码报告错误的原因是对于声明为的函数模板:

template <typename X>
void readAWSSettingOrPopulateDefault(AwsProperty<X> property, QString key
                                   , X default_val, QSettings settings
                                   , bool (*predicate)(X));

编译器必须使用这个模板参数从所有参数中推断出X -- propertydefault_val predicate -- 然后确保这些推断的类型是相同(即模板参数只有一个,可以容纳一种类型)。

然而,lambda 不是一个函数。它可以通过隐式转换转换为函数指针。模板参数推导不考虑转换(派生到基转换除外)。因此,编译器无法完成模板参数推导。

为了使您的代码正常工作,请将最后一次出现的X 放在非推导上下文中的函数指针类型参数声明中

template <typename T>
struct dont_deduce { using type = T; };

template <typename T>
using dont_deduce_t = typename dont_deduce<T>::type;

template <typename X>
void readAWSSettingOrPopulateDefault(AwsProperty<X> property, QString key
                                   , X default_val, QSettings settings
                                   , bool (*predicate)(dont_deduce_t<X>));

这样,编译器甚至不会尝试从 lambda 表达式推导出 X,而是使用来自 property/default_val 的类型,从而可以使用 lambda 到一个函数指针。也就是说,没有推论,同时,一个可以触发转换的已知函数签名。

【讨论】:

  • 我在开篇文章中添加了我的尝试,它与您的相似,但只使用一种通用模板类型。你明白为什么编译器会抱怨 lambda 匹配吗?
  • 非常感谢,经过一番研究,我发现这将成为 C++2X 的一部分。
  • @Curunir 是的,它是std::type_identity_t的替代品
猜你喜欢
  • 1970-01-01
  • 2018-09-21
  • 1970-01-01
  • 2014-05-20
  • 1970-01-01
  • 2010-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多