繁体   English   中英

C++ 模板 function 调用似乎更喜欢不太专业的调用

[英]C++ template function call seems to prefer the less specialized one

我试图通过使用 C++ 模板来简化我之前的一些 JSON 序列化,以在一定程度上减少样板代码。 一切都很顺利,直到我想序列化列表等类型,因为它们本身也是模板,并且似乎需要部分模板特化,而模板函数似乎不存在这种特化。

因此,我应用了我在这里找到的一个巧妙的小技巧: https://www.fluentcpp.com/2017/08/15/function-templates-partial-specialization-cpp/

namespace Support {
// These are in header files
template <typename T>
struct convertType{};

// Specialised template that serialises a list by iterating over its members
template <typename T>
QJsonValue toJsonValue(const QList<T> &source, convertType<QList<T>>) {
    QJsonArray result;
    for (auto it = source.cbegin(); it != source.cend(); it++) {
        result.push_back(*it);
    }
    return result;
}

// "Fallback" template that generates an assertion
template <typename T>
QJsonValue toJsonValue(const T &source, convertType<T>) {
    // This function should never be called.
    std::string msg = "toJsonValue called with unimplemented type ";
    msg += typeid (T).name();
    Q_ASSERT_X(false, "toJsonValue<T>", msg.c_str()); // Always asserts. 
    return QJsonValue();
}

// Convenience function
template<typename T>
QJsonValue toJsonValue(const T &source) {
    return toJsonValue<T>(source, convertType<T>{});
}

// This one is in the CPP file

// Integer
template <>
QJsonValue toJsonValue(const int &source, convertType<int>) {
    return QJsonValue(source);
}

} // NS Support

当我使用 integer 调用此模板时,如下所示:

qDebug() << Support::toJsonValue<int>(3713); // if not familiar with Qt, think as qDebug() being the same as std::cout.

正如预期的那样,这将输出“QJsonValue(double, 3713)”。

但是,当我尝试按如下方式传递列表时:

QList<int> foo = {1, 2, 3};
qDebug() << Support::toJsonValue<QList<int>>(foo);

在我看来,代码将采用最不专业的 function 模板,即生成断言的模板。 我不知道为什么会发生这种情况,因为我预计它将采用专门用于QList的 function 模板。

有谁知道为什么会这样? 我可能滥用模板吗?

我不知道为什么会发生这种情况,因为我预计它将采用专门用于 QList 的 function 模板。

有谁知道为什么会这样?

你打电话时

Support::toJsonValue<QList<int>>(foo);

以下“便利功能”匹配

template<typename T>
QJsonValue toJsonValue(const T &source) {
    return toJsonValue<T>(source, convertType<T>{});
}

TQList<int>

所以内部调用

toJsonValue<T>(source, convertType<T>{})

变得

toJsonValue<QList<int>>(source, convertType<QList<int>>{});
// ........^^^^^^^^^^^^
// ........^^^^^^^^^^^^  here is the problem

您明确规定T类型为QList<int>

所以调用不能匹配你的QList专业化

template <typename T>
QJsonValue toJsonValue(const QList<T> &source, convertType<QList<T>>)

其中模板参数T旨在为int ,即QList的模板参数。

您的调用只能匹配后备专业化

template <typename T>
QJsonValue toJsonValue(const T &source, convertType<T>)

建议:让我们进行模板推演。 我的意思是:不要在内部调用中显式模板参数

template<typename T>
QJsonValue toJsonValue(const T &source) {
    return toJsonValue(source, convertType<T>{}); 
} // ......^^^^^^^^^^^
  // ......^^^^^^^^^^^ no more "<T>" after toJsonValue

因此两个参数toJsonValue() function 都匹配(带有TQlist版本被推断为int和带有T的后备版本被推断为QList<int> )但应该选择更专业的( QList版本)。

这两个是等价的吗? 似乎您创建了重载而不是部分专业化。

// Integer
template <>
QJsonValue toJsonValue(const int &source, convertType<int>) {
    return QJsonValue(source);
}
// Integer
template <>
QJsonValue<int> toJsonValue(const int &source, convertType<int>) {
    return QJsonValue(source);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM