首页 > 解决方案 > 我想通过模板类的类型选择重载函数,方法是将类型存储在成员中。我可以这样做吗?

问题描述

我在这里有一个工作示例:

#include <QString>
#include <QUrl>
class Foobar
{
    explicit Foobar( QString fun ) { }
};

template<typename T>
class QPizza
{
public:
    explicit QPizza() { }
    QString value   () { return this->topping(m_T); }

protected:

    virtual QString topping(T*)
    {
        return "this is a T";
    }
    virtual QString topping(QString*)
    {
        return "this is a qstring";
    }
    virtual QString topping(QUrl   *)
    {
        return "This is a url";
    }
    virtual QString topping(Foobar *)
    {
        return "This is a foobar";
    }
private:
    T *m_T{nullptr};
};

这允许我执行以下代码:

qDebug() << QPizza<QString>().value() << QPizza<Foobar>().value() ;
// "this is a qstring" "This is a foobar"

这很棒,因为它允许我基本上进行专业化,而无需任何繁琐的模板语法。

这是问题所在:

    QString topping(QString ) // I'd rather have this
    QString topping(QString*) // instead of this because
    QPizza<QString>().value() // I want <QString> to be synonymous with (QString ), not (QString*)

但是,如果我更改T *m_T{nullptr}T m_T;,则QPizza<Foobar>()停止工作,因为它的构造函数需要一个参数。

有什么方法可以实现我的目标,这样如果我或其他任何人选择子类化,重载的过程会QString topping( <SomeType> );更直接一点吗?

谢谢。

标签: c++qttemplatesoverloadingmember-functions

解决方案


按类型分派有几种方式:

  • 功能专业化

    template <typename T>
    QString PizzaTopping() { return "this is a T"; }
    
    template <> QString PizzaTopping<QString>() { return "this is a qstring"; }
    template <> QString PizzaTopping<QUrl>() { return "this is a url"; }
    template <> QString PizzaTopping<Foobar>() { return "this is a foobar"; }
    

    虽然你不能部分专门化功能

  • 班级专业化

    template <typename T>
    struct PizzaTopping {
        QString operator() const { return "this is a T"; }
    };
    
    template <>
    struct PizzaTopping<QString> {
        QString operator() const { return "this is a qstring"; }
    };
    template <>
    struct PizzaTopping<QUrl> {
        QString operator() const { return "this is a url"; }
    };
    template <>
    struct PizzaTopping<Foobar> {
        QString operator() const { return "this is a foobar"; }
    };
    

    您甚至可以完全专业化成员,而不是完整的类(类似于上述方法)。

    template <>
    QString PizzaTopping<Foo>::operator() const { return "this is a foo"; }
    

    您可以对课程进行部分专业化。

    template <typename T>
    struct PizzaTopping<std::vector<T>> {
        QString operator() const {
            return "this is a vector. and for inner type, " + PizzaTopping<T>{}();
        }
    };
    
  • 标签调度(重载而不是特化):

    template <typename T> struct Tag{};
    
    template <typename T>
    QString PizzaTopping(Tag<T>) { return "this is a T"; }
    
    QString PizzaTopping(Tag<QString>) { return "this is a qstring"; }
    QString PizzaTopping(Tag<QUrl>) { return "this is a url"; }
    QString PizzaTopping(Tag<Foobar>) { return "this is a foobar"; }
    
    template <typename T>
    QString PizzaTopping(Tag<std::vector<T>>) {
        return "this is a vector, and for inner type, " + PizzaTopping(Tag<T>{});
    }
    

    它类似于您使用指针的方式(没有一些陷阱:例如,您不支持参考)。

有什么方法可以实现我的目标,这样如果我或其他任何人选择子类化,重载的过程会QString topping(<SomeType>);更直接一点吗?

如果PizzaTopping在您的类中(作为方法),则不能扩展到其他类型。

  • 如果您希望它出现在您的班级中,请使用专业化方式。
  • 将其移出课堂并选择您喜欢的调度方式。

推荐阅读