QT6 源(93)篇三:阅读与注释共用体类 QVariant 及其源代码,本类支持比较运算符 ==、!=。
(9) 本类支持比较运算符 ==、!= :
++可见, QString 类型里可存储多个 unicode 字符,即使只存储一个 unicode 字符也不等于 QChar。
(10)本源代码来自于头文件 qvariant . h :
#ifndef QVARIANT_H
#define QVARIANT_H#include <QtCore/qatomic.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qlist.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qmap.h>
#include <QtCore/qhash.h>
#include <QtCore/qstring.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qobject.h>
#ifndef QT_NO_DEBUG_STREAM
#include <QtCore/qdebug.h>
#endif
#ifndef QT_BOOTSTRAPPED
#include <QtCore/qbytearraylist.h>
#endif
#include <memory>
#include <type_traits>#if __has_include(<variant>) && __cplusplus >= 201703L
#include <variant>
#elif defined(Q_CLANG_QDOC)
namespace std { template<typename...> struct variant; }
#endifQT_BEGIN_NAMESPACEclass QBitArray;
class QDataStream;
class QDate;
class QDateTime;#if QT_CONFIG(easingcurve)class QEasingCurve;
#endifclass QLine;
class QLineF;
class QLocale;
class QTransform;
class QTime;
class QPoint;
class QPointF;
class QSize;
class QSizeF;
class QRect;
class QRectF;#if QT_CONFIG(regularexpression)class QRegularExpression;
#endif // QT_CONFIG(regularexpression)class QTextFormat;
class QTextLength;
class QUrl;
class QVariant;#ifndef QT_NO_DATASTREAM
Q_CORE_EXPORT QDataStream & operator >>(QDataStream & s, QVariant & p);
Q_CORE_EXPORT QDataStream & operator <<(QDataStream & s, const QVariant & p);
#endiftemplate<typename T> //先来一个全局模板函数。函数声明
inline T qvariant_cast(const QVariant &);#ifndef QT_MOC //下面的函数是存在的
template<typename T>
inline T qvariant_cast(const QVariant & v)
{QMetaType targetType = QMetaType::fromType<T>();if (v.d.type() == targetType)return v.d.get<T>();if constexpr (std::is_same_v<T,std::remove_const_t<std::remove_pointer_t<T>> const *>){using nonConstT = std::remove_const_t<std::remove_pointer_t<T>> *;QMetaType nonConstTargetType = QMetaType::fromType<nonConstT>();if (v.d.type() == nonConstTargetType)return v.d.get<nonConstT>();}T t{}; //定义一个空值,填充后返回QMetaType::convert(v.metaType(), v.constData(), targetType, & t);return t;
}template<> //模板特化
inline QVariant qvariant_cast<QVariant>(const QVariant & v)
{if (v.metaType().id() == QMetaType::QVariant)return * reinterpret_cast<const QVariant *>(v.constData());return v;
}
#endif/*
The QVariant class acts like a union for the most common Qt data types.由于C++禁止联合体包含具有非默认构造函数或析构函数的类型,因此大多数有趣的 Qt类不能在联合体中使用。
如果没有QVariant,这将给 Q0bject::property()和数据库工作等带来问题。QVariant对象一次只能持有单个类型的一个值(某些类型是多值的,例如字符串列表)。
你可以找出该变体持有的类型T,使用convert()将其转换为不同的类型,
使用toT()函数之-(例如toSize())获取其值,
并使用canConvert()检查该类型是否可以转换为特定类型。
名为 toT()的方法(例如 tolnt()和 toString())是常量。
如果您询问存储的类型,它们会返回存储对象的副本。
如果您询问可以从存储类型生成的类型,toT()会复制、转换并保留对象本身不变。
如果您询问无法从存储类型生成的类型,结果取决于类型;请查看函数文档以获取详细信息。你甚至可以将 QList<QVariant>和 QMap<QString,QVariant>值存储在一个变体中,
因此你可以轻松构建任意类型的任意复杂数据结构。
这非常强大和通用,但可能不如在标准数据结构中存储特定类型那样节省内存和提高速度。QVariant还支持空值的概念。如果变量不包含初始化值,或者包含空指针,则变量为null。QVariant 可以扩展以支持除 QMetaType::Type 枚举中提到的类型以外的其他类型。
有关详细信息,请参阅创建自定义 Qt 类型。enum QMetaType::Type { //定义了一个类内部的枚举类型// these are merged with QVariantQT_FOR_EACH_STATIC_TYPE(QT_DEFINE_METATYPE_ID)FirstCoreType = Bool, //= 1LastCoreType = QVariantPair, //= 58FirstGuiType = QFont, //=0x1000LastGuiType = QColorSpace, //=0x1017FirstWidgetsType = QSizePolicy, //=0x2000LastWidgetsType = QSizePolicy, //=0x2000HighestInternalId = LastWidgetsType, //=0x2000QReal = sizeof(qreal) == sizeof(double) ? Double : Float,//这里是在依托机器平台定义浮点数的默认类型UnknownType = 0,User = 65536};A Note on GUI Types:
因为 QVariant是 Qt Core 模块的一部分,所以它不能为 Qt GU 中定义的数据类型提供转换函数,
例如QColor、Qimage和 QPixmap。换句话说,没有toColor()函数。
相反,您可以使用 QVariant::value() 或模板函数 qvariant_cast()。例如:QVariant variant;...QColor color = variant.value<QColor>();到 QVariant)的反向转换是自动的(例如从 QColor),
对于 QVariant 支持的所有数据类型(包括与 GUl相关的类型):QColor color = palette().background().color();QVariant variant = color;Using canConvert() and convert() Consecutively连续地 :
当连续使用canConvert()和convert()时,canConvert()可能返回 true,但convert()返回 false。
这通常是因为 canConvert()只报告 QVariant 在给定合适数据时转换类型的一般能力;
仍然有可能提供实际上无法转换的数据。例如,当对包含字符串的变体调用 canConvert(QMetaType::fromType<int>())时,它会返回 true,
因为原则上 QVariant 能够将字符串和数字转换为整数。
但是,如果字符串包含非数字字符,则无法将其转换为整数,任何尝试转换的尝试都将失败。
因此,重要的是两个数都返回 true 以表示成功转换。*/class Q_CORE_EXPORT QVariant //正类开始定义
{
public: //这里首先定义了两个类中类。这是为了辅助本类中的数据成员的定义struct PrivateShared{private:inline PrivateShared() : ref(1) { }//私有构造函数public:alignas(8) QAtomicInt ref;// 8字节对齐的原子整数int offset; //本类的数据成员,一个整数,起名叫偏移量static PrivateShared * create( //本类的静态成员函数const QtPrivate::QMetaTypeInterface * type){Q_ASSERT(type);size_t size = type->size;size_t align = type->alignment;size += sizeof(PrivateShared);if (align > sizeof(PrivateShared)) {//The alignment is larger than the alignment we can guarantee//for the pointer directly following PrivateShared,//该对齐大于我们可以为直接跟随 PrivateShared的指针保证的对齐,//so we need to allocate some additional memory to be able to//fit the object into the available memory//with suitable alignment.//因此我们需要分配一些额外的内存,以便能够将对象适合到可用内存中,//并具有适当的对齐。size += align - sizeof(PrivateShared);}void * data = operator new(size); //分配了内存auto * ps = new (data) QVariant::PrivateShared();//在 ps 指针处构造了本类对象 QVariant::PrivateSharedps->offset = int( ((quintptr(ps) + sizeof(PrivateShared) + align - 1) &~(align - 1)) - quintptr(ps) );return ps;}static void free(PrivateShared * p) //静态的释放函数对应 create(){ p-> ~PrivateShared(); //执行了析构函数后,释放本类对象占据的内存operator delete(p) ;}const void * data() const //函数重载{ return reinterpret_cast<const unsigned char *>(this)+ offset; //把本类对象的地址加上 offset 偏移量后返回}void * data(){ return reinterpret_cast<unsigned char *>(this) + offset; }}; //完结 struct PrivateSharedstruct Private //又定义了这个类中类{ //先定义了一个静态的类内数据成员,3 个指针大小,目前是 24 字节static constexpr size_t MaxInternalSize = 3 * sizeof(void *);template<typename T> //又定义了这个静态的类内数据成员,还是模板变量static constexpr bool CanUseInternalSpace = ( //这是个布尔量QTypeInfo<T>::isRelocatable && //此布尔值sizeof(T) <= MaxInternalSize && //是三个与操作alignof(T) <= alignof(double) ); //的结果union //这是共用体,大小取最大的成员的类型的大小{ uchar data[MaxInternalSize] = {}; //定义 24字节的数组PrivateShared * shared ; //定义一个指针变量double _forAlignment ; //定义一个 double 成员// we want an 8byte alignment on 32bit systems as well} data; //此处为本类定义了一个 union 类型的数据成员,名字叫 dataquintptr is_shared : 1;quintptr is_null : 1; //这里又有三个整数成员quintptr packedType : sizeof(QMetaType) * 8 - 2;//静态成员函数,返回值是布尔量。看是否可以用内部空间的意思。static constexpr bool canUseInternalSpace(QtPrivate::QMetaTypeInterface *type){Q_ASSERT(type);return QMetaType::TypeFlags(type->flags) &QMetaType::RelocatableType &&size_t(type->size) <= MaxInternalSize &&size_t(type->alignment) <= alignof(double);}Private() noexcept : //本类的默认无参构造函数is_shared(false), is_null(true), packedType(0) {}explicit Private(QMetaType type) noexcept //有参构造函数: is_shared(false), is_null(false){quintptr mt = quintptr(type.d_ptr);Q_ASSERT((mt & 0x3) == 0);packedType = mt >> 2;}//似乎是构造函数又调用了构造函数explicit Private(int type) noexcept: Private(QMetaType(type)) {}//返回存储区的起始地址的意思const void * storage() const{ return is_shared ?data.shared->data() :& data.data; }//返回内部存储区的起始地址const void * internalStorage() const{ Q_ASSERT(is_shared);return & data.data;}// determine internal storage at compile timetemplate<typename T> //模板成员函数,返回左值引用const T & get() const{ return * static_cast<const T *>(storage()); }template<typename T> //接受赋值void set(const T & t){ *static_cast<T *>(CanUseInternalSpace<T> ?& data.data :data.shared->data()) = t;}inline QMetaType type() const{ //返回 QmetaType 类型return QMetaType(reinterpret_cast<QtPrivate::QMetaTypeInterface *>(packedType << 2));}inline int typeId() const { return type().id(); }inline QtPrivate::QMetaTypeInterface * //返回指针类型typeInterface() const{return reinterpret_cast<QtPrivate::QMetaTypeInterface *>(packedType << 2);}}; //完结 struct Privateprotected :Private d; //此处定义了本类的数据成员,名字叫 d//以下保护权限的成员函数,都没有官方注释void create(int type, const void *copy);void create(QMetaType type, const void *copy);bool equals(const QVariant &other) const;bool convert(int type, void *ptr) const;bool view(int type, void *ptr);public:typedef Private DataPtr; //为类名称起个新名称inline DataPtr & data_ptr() { return d; }inline const DataPtr & data_ptr() const { return d; }//Returns a pointer to the contained object//as a generic void* that can be written to.//This function detaches the QVariant.//When called on a null-QVariant,//the QVariant will not be null after the call.void * data();inline const void * data() const { return constData(); }const void * constData() const { return d.storage(); }public : //重点开始QVariant() noexcept : d() {} //默认构造函数~QVariant(); //本类的虚析构函数//本类的有参构造函数explicit QVariant(QMetaType type, const void * copy = nullptr);QVariant(const QVariant & other); //本类的 copy 构造函数QVariant(int i); //以下的构造函数表明,QVariant(uint ui); //本类可以接受一个普通数据,QVariant(qlonglong ll); //并完成构造与对象创建QVariant(qulonglong ull);QVariant(bool b);QVariant(double d);QVariant(float f);//说明可以以字符串构造本对象QVariant(const char * str) : QVariant(QString::fromUtf8(str)) {}QVariant(const QByteArray & bytearray); //构造函数QVariant(const QBitArray & bitarray );//说明可以以 QString 对象来构造本 QVariant 对象QVariant(const QString & string);QVariant(QLatin1String string);//拉丁文//容器里存储了多个字符串,说明可以拿容器对象来构造本 QVariant//using QStringList = QList<QString>;QVariant(const QStringList & stringlist);QVariant(QChar qchar);QVariant(QDate date) ; //以日期对象来构造本对象QVariant(QTime time) ; //以时间对象来构造本对象QVariant(const QDateTime & datetime);//再次以 QList、QMap、QHash容器对象来构造本对象//但要求键值对必须是 <字符串,QVariant> 形式QVariant(const QList<QVariant> &list); QVariant(const QMap<QString , QVariant> & map );QVariant(const QHash<QString, QVariant> & hash);#ifndef QT_NO_GEOM_VARIANT //经验证,确实没定义此宏QVariant(const QSize & size); //这些函数都被定义了//Constructs a new variant with a size value of val.QVariant(const QSizeF & size);//Constructs a new variant with a point value of val.QVariant(const QPoint & pt);QVariant(const QPointF & pt);//Constructs a new variant with a line value of val.QVariant(const QLine & line);QVariant(const QLineF & line);//Constructs a new variant with a rect value of val.QVariant(const QRect & rect);QVariant(const QRectF & rect);
#endif//Constructs a new variant with a locale value, l.QVariant(const QLocale & locale);QVariant(const QUuid & uuid);//宏定义中的##是预处理器的标记粘贴操作符,会把前后的标记连接起来。
//如feature是Thread,
//则QT_FEATURE_##feature就会拼接成QT_FEATURE_Thread
//通过除 0 错误来完成编译检查
//#define QT_CONFIG(feature) (1/QT_FEATURE_##feature == 1)
#if QT_CONFIG(regularexpression) //经验证允许正则表达式QVariant(const QRegularExpression & re);
#endif // QT_CONFIG(regularexpression)#if QT_CONFIG(easingcurve) //缓和曲线 easingcurveQVariant(const QEasingCurve & easing);
#endif#ifndef QT_BOOTSTRAPPED //似乎是用于 json 处理领域QVariant(const QUrl & url );QVariant(const QJsonValue & jsonValue );QVariant(const QJsonObject & jsonObject );QVariant(const QJsonArray & jsonArray );QVariant(const QJsonDocument & jsonDocument);
#endif // QT_BOOTSTRAPPED#if QT_CONFIG(itemmodel) //有此定义的QVariant(const QModelIndex & modelIndex);QVariant(const QPersistentModelIndex & modelIndex);
#endif//定义了本类的 copy 赋值运算符函数QVariant & operator=(const QVariant & other);//本类的移动构造函数inline QVariant(QVariant && other) noexcept : d(other.d){ other.d = Private(); }//看起来是以宏的形式,定义了本类的 移动赋值运算符函数QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(QVariant)
//#define QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_MOVE_AND_SWAP(Class) \
// Class &operator=(Class &&other) noexcept { \
// Class moved(std::move(other)); \
// swap(moved); \
// return *this; \
// }//与另一个 QVariant 对象进行交换数据的操作inline void swap(QVariant & other) noexcept{ qSwap(d, other.d); }//返回存储在变体中的值的 QMetaType。//本 QMetaType 已粗略整理源系列(7)以后再详细整理QMetaType metaType() const; //逐次往下调用//返回存储在本对象中的值的存储类型。这与metaType().id()相同。int typeId () const { return metaType().id(); }// QT 里确实对各种数据类型按整数进行了类型区分,故返回整数。int userType() const { return typeId(); }//对于QString 类型则返回 10//返回存储在变体中的类型的名称。//返回的字符串描述了用于存储数据的C++数据类型,const char * typeName() const;//如果变体类型可以转换为目标类型,则返回true。//在调用tolnt()、toBool() 方法时,会自动进行此类转换。bool canConvert(QMetaType targetType) const{ return QMetaType::canConvert(d.type(), targetType); }//将变体转换为请求的类型,type。//如果无法进行转换,则变体仍然会转换为请求的类型,但会变成空值,//类似于由 QVariant(Type)构造的状态。//如果变体类型的当前值已成功转换,则返回 true;否则返回 false。//包含指向从 QObject 派生的类型的指针的 QVariant,//如果对 type 描述的类型进行 qobject_cast成功,//则此函数也会转换并返回 true。请注意,//这仅适用于使用了 Q_OBJECT宏的 QOObiect 子类//注意:由于没有初始化或之前的转换失败了,//则这里的 OVariant转换也会失败为 null,将始终失败,//更改类型,保持 null,并返回 false。bool convert(QMetaType type); //注意形参为元类型bool canView(QMetaType targetType) const{ return QMetaType::canView(d.type(), targetType); }//Returns true if the storage type of this variant is not QMetaType::UnknownType;// otherwise returns false.inline bool isValid() const { return d.type().isValid(); }//Returns true if this is a null variant, false otherwise.//A variant is considered null if it contains no initialized value or a null pointer.bool isNull () const;inline bool isDetached() const //无官方注释{ return !d.is_shared || d.data.shared->ref.loadRelaxed() == 1; }void detach(); //似乎是取消隐式共享的意思,为修改写入做准备//Convert this variant to type QMetaType::UnknownType and free up any resources used.void clear (); //本函执行后对 isValid()返回 false,对 isNull () 返回true//Returns the variant as an int if the variant has QMetaType::Int()等,//otherwise returns 0. 转换失败则返回 0//If ok is non-null: * ok is set to true if the value could be converted to an int;// otherwise * ok is set to false.int toInt (bool * ok = nullptr) const;uint toUInt (bool * ok = nullptr) const;qlonglong toLongLong (bool * ok = nullptr) const; //这些都类似,不再详细注释了qulonglong toULongLong(bool * ok = nullptr) const;double toDouble (bool * ok = nullptr) const;float toFloat (bool * ok = nullptr) const;qreal toReal (bool * ok = nullptr) const;bool toBool () const;QString toString () const;QChar toChar () const;QByteArray toByteArray () const;QBitArray toBitArray () const;QStringList toStringList() const;QDate toDate () const;QTime toTime () const;QDateTime toDateTime() const;QList<QVariant> toList() const; //QList<QVariant>QMap<QString , QVariant> toMap () const;QHash<QString, QVariant> toHash() const;//Returns the variant as a QUuid//if the variant has type() QMetaType::QUuid,//QMetaType::QByteArray or QMetaType::QString;//otherwise returns a default-constructed QUuid.QUuid toUuid() const;//Returns the variant as a QLocale//if the variant has userType() QMetaType::QLocale;//otherwise returns an invalid QLocale.QLocale toLocale() const;#ifndef QT_NO_GEOM_VARIANT //看来是没定义,#if 有效QPoint toPoint () const;QPointF toPointF() const;QRect toRect () const;QRectF toRectF () const;QSize toSize () const;QSizeF toSizeF () const;QLine toLine () const;QLineF toLineF() const;
#endif //#ifndef QT_NO_GEOM_VARIANT#if QT_CONFIG(regularexpression) //正则表达式QRegularExpression toRegularExpression() const;
#endif // QT_CONFIG(regularexpression)#if QT_CONFIG(easingcurve) //缓动曲线QEasingCurve toEasingCurve() const;
#endif#ifndef QT_BOOTSTRAPPED //此 if成立,面向 json 的,存在这些成员函数QUrl toUrl () const;QJsonValue toJsonValue () const;QJsonObject toJsonObject () const;QJsonArray toJsonArray () const;QJsonDocument toJsonDocument() const;
#endif // QT_BOOTSTRAPPED#if QT_CONFIG(itemmodel) //经测试是有这个宏定义的QModelIndex toModelIndex () const;QPersistentModelIndex toPersistentModelIndex() const;
#endif#ifndef QT_NO_DATASTREAMvoid load(QDataStream & ds); //读void save(QDataStream & ds) const; //写
#endif#if QT_DEPRECATED_SINCE(6, 0) //里面的都是废弃的成员函数//.....全部删除了
#endif //#if QT_DEPRECATED_SINCE(6, 0)//template<typename T> //先来一个全局模板函数。函数声明//inline T qvariant_cast(const QVariant &);template<typename T> //注意,这是模板成员函数, T 可以为任何类型inline T value() const { return qvariant_cast<T>(*this); }void setValue(const QVariant & avalue) { * this = avalue ; }void setValue( QVariant && avalue) { * this = std::move(avalue); }/*
template <bool _Test, class _Ty = void>
struct enable_if {}; // no member "type" when !_Testtemplate <class _Ty> // type is _Ty for _Test
struct enable_if<true, _Ty> { using type = _Ty; };template <bool _Test, class _Ty = void> //真才返回 T 或 void类型
using enable_if_t = typename enable_if<_Test, _Ty>::type;
//-----------------------------------------------------------------
template <class, class>
bool is_same_v = false;template <class _Ty>
bool is_same_v<_Ty, _Ty> = true;
*/template<typename T, typename = std::enable_if_t<!std::is_same_v< std::decay_t<T>, QVariant >> >void setValue(T && avalue) //似乎是要求 T 不能为 QVariant类型{using VT = std::decay_t<T>;QMetaType metaType = QMetaType::fromType<VT>();// If possible we reuse the current QVariant private.if (isDetached() && d.type() == metaType) {*reinterpret_cast<VT *>(const_cast<void *>(constData()))= std::forward<T>(avalue);} else {*this = QVariant::fromValue<VT>(std::forward<T>(avalue));}}//Stores a copy of value.//If T is a type that QVariant doesn't support,//QMetaType is used to store the value.//A compile error will occur if QMetaType doesn't handle the type.//Returns a mutable view of template type T on the stored value.//Call canView() to find out whether such a view is supported.//If no such view can be created,//returns the stored value converted to the template type T.//Call canConvert() to find out whether a type can be converted.//If the value can neither be viewed nor converted,//a default-constructed value will be returned.template<typename T>inline T view(){ T t{};QMetaType::view(metaType(), data(), QMetaType::fromType<T>(), &t);return t;}//Returns true if T can be cast to the requested type, type.//Such casting is done automatically when calling the// toInt(), toBool(), ... methods.template<typename T>bool canConvert() const{ return canConvert(QMetaType::fromType<T>()); }template<typename T>bool canView() const //无官方注释{ return canView(QMetaType::fromType<T>()); }//返回值是本 QVariant 类型,本函数的意思是根据形参构造本类型。//Returns a QVariant containing a copy of value.//Behaves exactly like setValue() otherwise.template<typename T>static inline auto fromValue(const T & value)-> std::enable_if_t<std::is_copy_constructible_v<T>, QVariant>{return QVariant(QMetaType::fromType<T>(), std::addressof(value));}template<>inline QVariant fromValue(const QVariant & value) { return value; }template<>inline QVariant fromValue(const std::monostate &) { return QVariant(); }template<typename... Types>static inline QVariant fromStdVariant(const std::variant<Types...> & value){if (value.valueless_by_exception())return QVariant();return std::visit([](const auto &arg) { return fromValue(arg); }, value);}public://QPartialOrdering::Unordered//QPartialOrdering::Less//QPartialOrdering::Equivalent//QPartialOrdering::Greaterstatic QPartialOrdering compare(const QVariant & lhs, const QVariant & rhs);private: //定义了友元函数friend inline bool operator==(const QVariant & a, const QVariant & b){ return a.equals(b); }friend inline bool operator!=(const QVariant & a, const QVariant & b){ return !a.equals(b); }#ifndef QT_NO_DEBUG_STREAM //本函有效的template <typename T> //即本变量可以被插入输入到 qDebug 里friend auto operator<<(const QDebug & debug, const T & variant)-> std::enable_if_t<std::is_same_v<T, QVariant>, QDebug>{return variant.qdebugHelper(debug);}QDebug qdebugHelper(QDebug) const;
#endif//Returns the given value converted to the template type T.//This function is equivalent to QVariant::value().template<typename T>friend inline T qvariant_cast(const QVariant &);private: //一些私有成员函数// force compile error, prevent QVariant(bool) to be calledinline QVariant(void *) = delete; //不支持存储布尔型啊// QVariant::Type is marked as \obsolete,// but we don't want to provide a constructor from its intended replacement,// QMetaType::Type, instead,// because the idea behind these constructors// is flawed in the first place.// But we also don't want QVariant(QMetaType::String) to compile// and falsely be an int variant, so delete this constructor://QVariant::Type 被标记为 \obsolete,//但我们不想从其意图的替代者QMetaType::Type 中提供构造函数,//因为这些构造函数背后的想法从一开始就是有缺陷的。//但我们也不希望 QVariant(QMetaType::String)编译并错误地成为 int 变体,//因此删除这个构造函数:QVariant(QMetaType::Type) = delete;//These constructors don't create QVariants of the type associated with the enum,//as expected, but they would create// a QVariant of type int with the value of the enum value.// Use QVariant v = QColor(Qt::red) instead of QVariant v = Qt::red for example.//这些构造函数不会像预期的那样创建与枚举类型关联的 QVariants,//但它们会创建-个类型为 int的 OVariant,其值为枚举值。//例如,使用 QVariantv=QColor(Ot::red)而不是 OVariantv=Qt::red。QVariant(Qt::GlobalColor) = delete;QVariant(Qt::BrushStyle) = delete;QVariant(Qt::PenStyle) = delete;QVariant(Qt::CursorShape) = delete;#ifdef QT_NO_CAST_FROM_ASCII //经测试本宏是没有定义的// force compile error when implicit conversion is not wantedinline QVariant(const char *) = delete; //所以此函数是没有定义的
#endif}; //完结 class QVariant !!!!!!!!!
Q_DECLARE_SHARED(QVariant)namespace QtPrivate {
class Q_CORE_EXPORT QVariantTypeCoercer
{
public:const void *convert(const QVariant &value, const QMetaType &type);const void *coerce(const QVariant &value, const QMetaType &type);private:QVariant converted;
};
}template<typename Pointer>
class QVariantRef
{
private:const Pointer *m_pointer = nullptr;public:explicit QVariantRef(const Pointer *reference) : m_pointer(reference) {}QVariantRef(const QVariantRef &) = default;QVariantRef(QVariantRef &&) = default;~QVariantRef() = default;operator QVariant() const;QVariantRef &operator=(const QVariant &value);QVariantRef &operator=(const QVariantRef &value){ return operator=(QVariant(value)); }QVariantRef &operator=(QVariantRef &&value) { return operator=(QVariant(value)); }friend void swap(QVariantRef a, QVariantRef b){QVariant tmp = a;a = b;b = std::move(tmp);}
};class Q_CORE_EXPORT QVariantConstPointer
{
private:QVariant m_variant;public:explicit QVariantConstPointer(QVariant variant);QVariant operator*() const;const QVariant *operator->() const;
};template<typename Pointer>
class QVariantPointer
{
private:const Pointer *m_pointer = nullptr;public:explicit QVariantPointer(const Pointer *pointer) : m_pointer(pointer) {}QVariantRef<Pointer> operator*() const { return QVariantRef<Pointer>(m_pointer); }Pointer operator->() const { return *m_pointer; }
};QT_END_NAMESPACE#endif // QVARIANT_H
(11)
谢谢
相关文章:
QT6 源(93)篇三:阅读与注释共用体类 QVariant 及其源代码,本类支持比较运算符 ==、!=。
(9) 本类支持比较运算符 、! : 可见, QString 类型里可存储多个 unicode 字符,即使只存储一个 unicode 字符也不等于 QChar。 (10)本源代码来自于头文件 qvariant . h : #ifndef Q…...
Qt开发经验 --- 避坑指南(13)
文章目录 [toc]1 安装Qt creator后无法使用debug调试2 安装VS后之间安装自带的Windows SDK3 Qt配置ssl4 ubuntu编译linuxdeployqt 更多精彩内容👉内容导航 👈👉Qt开发经验 👈 1 安装Qt creator后无法使用debug调试 安装最新版本Q…...
go 通过汇编学习atomic原子操作原理
文章目录 概要一、原理1.1、案例1.2、关键汇编 二、LOCK汇编指令2.1、 LOCK2.2、 原理2.2.1、 缓存行2.2.2、 缓存一致性之MESI协议2.2.3、lock原理 三、x86缓存发展四、x86 DMA发展参考 概要 在并发操作下,对一个简单的aa2的操作都会出错,这是因为这样…...
LOJ 6346 线段树:关于时间 Solution
Description 给定序列 a ( a 1 , a 2 , ⋯ , a n ) a(a_1,a_2,\cdots,a_n) a(a1,a2,⋯,an),另有一个存储三元组的列表 L L L. 有 m m m 个操作分两种: add ( l , r , k ) \operatorname{add}(l,r,k) add(l,r,k):将 ( l , r , …...
Python----神经网络(基于Alex Net的花卉分类项目)
一、基于Alex Net的花卉分类 1.1、项目背景 在当今快速发展的科技领域,计算机视觉已成为一个备受关注的研究方向。随着深度学习技术的不断进步,图像识别技术得到了显著提升,广泛应用于医疗、安防、自动驾驶等多个领域。其中,花卉…...
影刀RPA开发-魔法指令-玩转图片识别
聊聊天,就能生成指令! 1. 影刀RPA提取图片内容的方式 官方AI识别 集成的第三方识别指令 免费的识别指令 使用python自己编写识别代码,自己安装第三方库 import easyocr# 创建一个 EasyOCR 识别器,指定同时识别中文(简…...
从零开始开发纯血鸿蒙应用之XML解析
从零开始开发纯血鸿蒙应用 〇、前言一、鸿蒙SDK中的 XML API1、ohos.xml2、ohos.convertxml 三、XML 解析实践1、源数据结构2、定义映射关系3、定义接收对象4、获取文章信息 四、总结 〇、前言 在前后端的数据传输方面,论格式化形式,JSON格式自然是首选…...
运算放大器稳定性分析
我们常见的运放电路大多是在闭环状态。那么就必然遵循闭环控制系统的基本原理。闭环控制系统的核心是通过反馈来调节系统的输出,使其更接近期望值。 本文从闭环控制系统的角度,画出同相、反相差分电路的经典控制框图。有了控制框图就可以利用经典控制理论…...
python【扩展库】websockets
文章目录 介绍基础教程安装websockets接收与发送消息介绍 websockets基于python构建websocket服务、客户端的扩展库;官方文档;优点是正确性(严格测试,100%分支覆盖)、简单性(自管理连接)、健壮性、高性能(C扩展加速内存操作),双向通信;基于(python标准异步io框架)…...
leetcode 454. 4Sum II
题目描述 代码: class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {unordered_map<int,int> table;int temp 0;for(auto n1:nums1){fo…...
MCP 传输层代码分析
MCP 传输层代码分析 MCP 整体架构说明 引用官方文档原文:Model Context Protocol (MCP) 构建在一个灵活且可扩展的架构上,使 LLM 应用和集成之间的无缝通信成为可能。具体架构细节可以参考文档(核心架构 - MCP 中文文档)。MCP 采…...
OBS studio 减少音频中的杂音(噪音)
1. 在混音器中关闭除 麦克风 之外的所有的音频输入设备 2.在滤镜中增加“噪声抑制”和“噪声门限”...
java的Stream流处理
Java Stream 流处理详解 Stream 是 Java 8 引入的一个强大的数据处理抽象,它允许你以声明式方式处理数据集合(类似于 SQL 语句),支持并行操作,提高了代码的可读性和处理效率。 一、Stream 的核心概念 1. 什么是 Str…...
Windows使用虚拟环境执行sh脚本
在代码文件夹git bash here echo ‘export PATH“/f/anaconda/Scripts:$PATH”’ >> ~/.bashrc echo ‘source /f/anaconda/etc/profile.d/conda.sh’ >> ~/.bashrc source ~/.bashrc conda路径确认 where conda conda activate mmt bash ./online.sh感谢gpt记录…...
Transformer Decoder-Only 算力FLOPs估计
FLOPs和FLOPS的区别 FLOPs (Floating Point Operations)是指模型或算法执行过程中总的浮点运算次数,单位是“次”FLOPS (Floating Point Operations Per Second)是指硬件设备(如 GPU 或 CPU)每…...
数字电子技术基础(五十七)——边沿触发器
目录 1 边沿触发器 1.1 边沿触发器简介 1.1.1 边沿触发器的电路结构 1.3 边沿触发的D触发器和JK触发器 1.3.1 边沿触发的D型触发器 1.3.2 边沿触发的JK触发器 1 边沿触发器 1.1 边沿触发器简介 对于时钟触发的触发器来说,始终都存在空翻的现象,抗…...
05.three官方示例+编辑器+AI快速学习three.js webgl - animation - skinning - ik
本实例主要讲解内容 这个Three.js示例展示了**反向运动学(Inverse Kinematics, IK)**在3D角色动画中的应用。通过加载一个角色模型,演示了如何使用IK技术实现自然的肢体运动控制,如手部抓取物体的动作。 核心技术包括: CCD反向运动学求解器…...
MYSQL数据库集群高可用和数据监控平台
项目环境 项目拓扑结构 软硬件环境清单 软硬件环境清单 软硬件环境清单 主机名IP硬件软件 master1 192.168.12.130 VIP:192.168.12.200 cpu:1颗2核 内 存:2GB HDD:20GB 网 络:NAT VmWare17 OpenEuler22.03 SP4 MySql8.0.3…...
《异常链机制详解:如何优雅地传递Java中的错误信息?》
大家好呀!👋 作为一名Java开发者,相信你一定见过各种奇奇怪怪的异常报错。但有没有遇到过这样的情况:明明只调用了一个方法,却看到异常信息像俄罗斯套娃一样一层层展开?🤔 这就是我们今天要讲的…...
MySQL 数据库集群部署、性能优化及高可用架构设计
MySQL 数据库集群部署、性能优化及高可用架构设计 集群部署方案 1. 主从复制架构 传统主从复制:配置一个主库(Master)和多个从库(Slave)GTID复制:基于全局事务标识符的复制,简化故障转移半同步复制:确保至少一个从库接收到数据…...
什么是深度神经网络
深度神经网络(DNN)详细介绍 1. 定义与核心原理 深度神经网络(Deep Neural Network, DNN)是一种具有多个隐藏层的人工神经网络模型,其核心在于通过层次化的非线性变换逐步提取输入数据的高层次抽象特征。与浅层神经网络相比,DNN的隐藏层数量通常超过三层,例如VGGNet、R…...
深入解析PyTorch中MultiheadAttention的隐藏参数add_bias_kv与add_zero_attn
关键背景 最近在学习pytorch中的源码尤其是nn.modules下算子的实现,针对activation.py下MultiheadAttention下有两个不常见的参数的使用比较有趣,因为时序领域很少使用这两个参数(add_bias_kv和add_zero_attn),但是其…...
最大化效率和性能:AKS 中节点池的强大功能
什么是节点池 在 Azure Kubernetes 服务 (AKS) 中,相同配置的节点会被分组到节点池中。这些节点池包含运行应用程序的底层虚拟机。创建 AKS 集群时,您需要定义初始节点数及其大小 (SKU)。随着应用程序需求的变化,您可能需要更改节点池的设置…...
用户态到内核态:Linux信号传递的九重门(一)
1. 信号的认识 1.1. 信号的特点 异步通知:信号是异步的,发送信号的进程无需等待接收进程的响应。预定义事件:每个信号对应一个预定义的事件(如终止、中断、段错误等)。 轻量级:信号不携带大量数据…...
c语言第一个小游戏:贪吃蛇小游戏01
hello啊大家好 今天我们用一个小游戏来增强我们的c语言! 那就是贪吃蛇 为什么要做一个贪吃蛇小游戏呢? 因为这个小游戏所涉及到的知识有c语言的指针、数组、链表、函数等等可以让我们通过这个游戏来巩固c语言,进一步认识c语言。 一.我们先…...
JAVA EE_网络原理_网络层
晨雾散尽,花影清晰。 ----------陳長生. ❀主页:陳長生.-CSDN博客❀ 📕上一篇:数据库Mysql_联…...
前端性能指标及优化策略——从加载、渲染和交互阶段分别解读详解并以Webpack+Vue项目为例进行解读
按照加载阶段、渲染阶段和交互阶段三个维度进行系统性阐述: 在现代 Web 开发中,性能不再是锦上添花,而是决定用户体验与业务成败的关键因素。为了全面监控与优化网页性能,我们可以将性能指标划分为加载阶段、渲染阶段、和交互阶段…...
Flink 系列之十五 - 高级概念 - 窗口
之前做过数据平台,对于实时数据采集,使用了Flink。现在想想,在数据开发平台中,Flink的身影几乎无处不在,由于之前是边用边学,总体有点混乱,借此空隙,整理一下Flink的内容,…...
控制台打印带格式内容
1. 场景 很多软件会在控制台打印带颜色和格式的文字,需要使用转义符实现这个功能。 2. 详细说明 2.1.转义符说明 样式开始:\033[参数1;参数2;参数3m 可以多个参数叠加,若同一类型的参数(如字体颜色)设置了多个&…...
Linux为啥会重新设置中断请求号与中断向量号之间的关系?
Linux内核重新设置中断请求号(IRQ)与中断向量号之间的关系,主要出于以下核心原因和设计考量: 1. 硬件多样性与抽象需求 硬件中断号(HW Interrupt ID)的差异 不同处理器架构的中断控制器(…...
自然语言处理NLP中的连续词袋(Continuous bag of words,CBOW)方法、优势、作用和程序举例
自然语言处理NLP中的连续词袋(Continuous bag of words,CBOW)方法、优势、作用和程序举例 目录 自然语言处理NLP中的连续词袋(Continuous bag of words,CBOW)方法、优势、作用和程序举例一、连续词袋( Cont…...
计算机网络笔记(二十二)——4.4网际控制报文协议ICMP
4.4.1ICMP报文的种类 ICMP(Internet Control Message Protocol)是IP协议的辅助协议,主要用于传递控制消息、错误报告和诊断信息。其报文分为两大类:查询报文和错误报告报文。 1. 错误报告报文(Error Messages&#x…...
【AI论文】作为评判者的感知代理:评估大型语言模型中的高阶社会认知
摘要:评估大型语言模型(LLM)对人类的理解程度,而不仅仅是文本,仍然是一个开放的挑战。 为了弥合这一差距,我们引入了Sentient Agent作为评判者(SAGE),这是一个自动评估框…...
Kubernetes生产实战(二十七):精准追踪Pod数据存储位置
在生产环境中,快速定位Pod数据的物理存储位置是运维人员的基本功。本文将揭秘Kubernetes存储系统的核心原理,并提供一套经过实战检验的定位方法体系。 一、存储架构全景图 K8S存储架构 Pod --> Volume Mount --> PVC --> PV --> Storage P…...
极新携手火山引擎,共探AI时代生态共建的破局点与增长引擎
在生成式AI与行业大模型的双重驱动下,人工智能正以前所未有的速度重构互联网产业生态。从内容创作、用户交互到商业决策,AI技术渗透至产品研发、运营的全链条,推动效率跃升与创新模式变革。然而,面对AI技术迭代的爆发期࿰…...
[SIGPIPE 错误] 一个 Linux socket 程序,没有任何报错打印直接退出程序
1. 问题 在编写一个程序的时候,当然程序很复杂,遇到了一个 Linux socket 程序,没有任何报错打印直接退出程序,但是在程序里面我有很多 error log ,在程序退出的时候完全没有打印。为了说明问题,我编写了一…...
Qt 界面优化(绘图)
目录 1. 绘图基本概念2. 绘制各种形状2.1 绘制线段2.2 绘制矩形2.3 绘制圆形2.4 绘制文本2.5 设置画笔2.6 设置画刷 3. 绘制图片3.1 绘制简单图片3.2 平移图片3.3 缩放图片3.4 旋转图片 4. 其他设置4.1 移动画家位置4.2 保存/加载画家的状态 5. 特殊的绘图设备5.1 QPixmap5.2 Q…...
AQS(AbstractQueuedSynchronizer)解析
文章目录 一、AQS简介二、核心设计思想2.1 核心设计思想回顾2.2 CLH锁队列简介2.3 AQS对CLH队列的改动及其原因 三、核心组件详解3.1 state 状态变量3.2 同步队列 (FIFO双向链表) 四、核心方法深度解析4.1 获取同步状态 (独占模式) - acquire(int arg)4.2 释放同步状态 (独占模…...
Java并发编程常见问题与陷阱解析
引言 随着计算机硬件技术的飞速发展,多核处理器已经变得普遍,Java并发编程的重要性也日益凸显。然而,多线程编程并非易事,其中充满了许多潜在的问题和陷阱。作为一名Java开发工程师,掌握并发编程的常见问题及其解决方案…...
DEEPPOLAR:通过深度学习发明非线性大核极坐标码(1)
原文:《DEEPPOLAR: Inventing Nonlinear Large-Kernel Polar Codes via Deep Learning》 摘要 信道编码设计的进步是由人类的创造力推动的,而且恰如其分地说,这种进步是零星的。极性码是在Arikan极化核的基础上开发的,代表了编码…...
Java多态详解
Java多态详解 什么是多态? 比如我们说:“驾驶一辆车”,有人开的是自行车,有人开的是摩托车,有人开的是汽车。虽然我们都说“开车”,但“怎么开”是由具体的车类型决定的:“开”是统一的动作&a…...
go程序编译成动态库,使用c进行调用
以下是使用 Go 语言打包成 .so 库并使用 C 语言调用的完整步骤: 1. Go 语言打包成 .so 库 (1)编写 Go 代码 创建一个 Go 文件(如 calculator.go),并定义需要导出的函数。导出的函数名必须以大写字母开头…...
iVX:图形化编程与组件化的强强联合
在数字化浪潮中,软件开发范式正经历着从文本到图形的革命性转变。iVX 作为国产可视化编程领域的领军者,以 “图形化逻辑 组件化架构” 的双重创新,重新定义了软件开发的效率边界。其技术突破不仅体现在开发方式的革新,更通过一系…...
华为配置篇-RSTP/MSTP实验
MSTP 一、简介二、常用命令总结三、实验 一、简介 RSTP(快速生成树协议) RSTP(Rapid Spanning Tree Protocol)是 STP 的改进版本,基于 IEEE 802.1w 标准,核心目标是解决传统 STP 收敛速度慢的问…...
端口号被占用怎么解决
windows环境下端口号被占用怎么解决 win r 快捷键打开cmd输入netstat -ano|findstr 端口号 通过这个命令找到pidtaskkill /pid pid端口号 /t /f 如下图所示 命令解读 netstat 是一个网络统计工具,它可以显示协议统计信息和当前的TCP/IP网络连接。 -a 参数告诉 nets…...
GO语言-导入自定义包
文章目录 1. 项目目录结构2. 创建自定义包3. 初始化模块4. 导入自定义包5. 相对路径导入 在Go语言中导入自定义包需要遵循一定的目录结构和导入规则。以下是详细指南(包含两种方式): 1. 项目目录结构 方法1:适用于Go 1.11 &#…...
ES常识5:主分词器、子字段分词器
文章目录 一、主分词器:最基础的文本处理单元主分词器的作用典型主分词器示例 二、其他类型的分词器:解决主分词器的局限性1. 子字段分词器(Multi-fields)2. 搜索分词器(Search Analyzer)3. 自定义分词器&a…...
NoSQL数据库技术与应用复习总结【看到最后】
第1章 初识NoSQL 1.1 大数据时代对数据存储的挑战 1.高并发读写需求 2.高效率存储与访问需求 3.高扩展性 1.2 认识NoSQL NoSQL--非关系型、分布式、不提供ACID的数据库设计模式 NoSQL特点 1.易扩展 2.高性能 3.灵活的数据模型 4.高可用 NoSQL拥有一个共同的特点&am…...
单片机-STM32部分:12、I2C
飞书文档https://x509p6c8to.feishu.cn/wiki/MsB7wLebki07eUkAZ1ec12W3nsh 一、简介 IIC协议,又称I2C协议,是由PHILP公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备,IIC属于半双工同步通信方式。 IIC是一种同步…...
【英语笔记(四)】诠释所有16种英语时态,介绍每种时态下的动词变形!!含有所有时态的的动词变形汇总表格
1 时态的单词构成 1.1 现在 1.1.1 一般现在时态 动词原形动词原形s(第三人称单数) 1.1.1.1 表达事实 I eat carrots. 我吃胡萝卜:我是吃胡萝卜这种食物的.(这个是事实陈述) The rabbit eats carrots. 兔子吃胡萝卜…...