কিউটি 5-তে ওভারলোড হওয়া সংকেত এবং স্লটগুলি সংযুক্ত করা হচ্ছে


133

নিউ সিগন্যাল স্লট সিনট্যাক্সে বর্ণিত কিউটি 5 তে নতুন সিগন্যাল / স্লট সিনট্যাক্স (পয়েন্টার টু মেম্বার ফাংশন ব্যবহার করে) নিয়ে কুঁচকে উঠতে আমার সমস্যা হচ্ছে । আমি এটি পরিবর্তন করার চেষ্টা করেছি:

QObject::connect(spinBox, SIGNAL(valueChanged(int)),
                 slider, SLOT(setValue(int));

এটি:

QObject::connect(spinBox, &QSpinBox::valueChanged,
                 slider, &QSlider::setValue);

তবে আমি এটি সংকলনের চেষ্টা করার সময় একটি ত্রুটি পেয়েছি:

ত্রুটি: কল করার জন্য কোনও মিল নেই function QObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int))

আমি লিনাক্সে ঝনঝন এবং জিসিসি দিয়ে চেষ্টা করেছি, দুটোই দিয়েছি -std=c++11

আমি কী ভুল করছি এবং আমি কীভাবে এটি ঠিক করতে পারি?


যদি আপনার সিনট্যাক্সটি সঠিক হয়, তবে কেবলমাত্র ব্যাখ্যাটি হ'ল আপনি Qt5 লাইব্রেরিতে লিঙ্ক করছেন না, তবে এর পরিবর্তে Qt4 করছেন। 'প্রকল্পগুলি' পৃষ্ঠায় কিউটিক্রিটরের সাথে যাচাই করা সহজ।
ম্যাট ফিলিপস

আমি কিউবজেক্ট (কিউস্পিনবক্স ইত্যাদি) এর কয়েকটি সাবক্লাস অন্তর্ভুক্ত করেছি যাতে কিউবজেক্টটি অন্তর্ভুক্ত করা উচিত ছিল। আমি যুক্ত করার চেষ্টা করেছি যা পাশাপাশি অন্তর্ভুক্ত রয়েছে এবং এটি এখনও সংকলন করবে না।
dtruby

এছাড়াও, আমি অবশ্যই Qt 5 এর সাথে সংযুক্ত করছি, আমি Qt স্রষ্টা ব্যবহার করছি এবং যে দুটি কিট আমি উভয়ের সাথে পরীক্ষা করছি তাদের Qt 5.0.1 এর Qt সংস্করণ হিসাবে তালিকাভুক্ত করা হয়েছে।
dtruby

উত্তর:


244

এখানে সমস্যাটি হ'ল সেই নামের সাথে দুটি সংকেত রয়েছে: QSpinBox::valueChanged(int)এবং QSpinBox::valueChanged(QString)। কিউটি 5.7 থেকে, পছন্দসই ওভারলোডটি নির্বাচন করতে সহায়ক ফাংশন সরবরাহ করা হয়, যাতে আপনি লিখতে পারেন

connect(spinbox, qOverload<int>(&QSpinBox::valueChanged),
        slider, &QSlider::setValue);

Qt 5.6 এবং তার আগের জন্য, আপনি Qt বলতে হবে যে আপনি কোনটি বেছে নিতে চান তা সঠিক প্রকারে কাস্ট করে:

connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
        slider, &QSlider::setValue);

আমি জানি, এটা কুশ্রী । তবে এর আশেপাশে কোনও উপায় নেই। আজকের পাঠটি হ'ল: আপনার সংকেত এবং স্লটগুলি ওভারলোড করবেন না!


সংযোজন : theালাই সম্পর্কে সত্যিই বিরক্তিকর কি তা

  1. একজন ক্লাসের নামটি পুনরাবৃত্তি করে
  2. একটিকে সাধারণত void(সংকেতগুলির জন্য) হলেও রিটার্ন মান নির্দিষ্ট করতে হয় ।

তাই আমি মাঝে মাঝে নিজেকে এই সি ++ 11 স্নিপেট ব্যবহার করে দেখতে পেয়েছি:

template<typename... Args> struct SELECT { 
    template<typename C, typename R> 
    static constexpr auto OVERLOAD_OF( R (C::*pmf)(Args...) ) -> decltype(pmf) { 
        return pmf;
    } 
};

ব্যবহার:

connect(spinbox, SELECT<int>::OVERLOAD_OF(&QSpinBox::valueChanged), ...)

আমি ব্যক্তিগতভাবে এটি সত্যিই দরকারী না বলে মনে করি। আমি আশা করি যখন পিএমএফ নেওয়ার ক্রিয়াকলাপটি স্বয়ংক্রিয়ভাবে পূর্ণ করা হবে তখন নির্মাতা (বা আপনার আইডিই) স্বয়ংক্রিয়ভাবে সঠিক কাস্টটি প্রবেশ করবে তখন এই সমস্যাটি নিজে থেকে দূরে চলে যাবে I তবে এর মধ্যে ...

দ্রষ্টব্য: পিএমএফ-ভিত্তিক সংযোগ সিনট্যাক্সের জন্য সি ++ 11 লাগবে না !


সংযোজন 2 : Qt 5.7 সাহায্যকারী ফাংশন এটিকে প্রশমিত করার জন্য যুক্ত করা হয়েছে, উপরের আমার কার্যকারিতার পরে মডেল করা হয়েছে। প্রধান সহায়ক হ'ল qOverload( আপনিও পেয়েছেন qConstOverloadএবং পেয়েছেন qNonConstOverload)।

ব্যবহারের উদাহরণ (ডক্স থেকে):

struct Foo {
    void overloadedFunction();
    void overloadedFunction(int, QString);
};

// requires C++14
qOverload<>(&Foo:overloadedFunction)
qOverload<int, QString>(&Foo:overloadedFunction)

// same, with C++11
QOverload<>::of(&Foo:overloadedFunction)
QOverload<int, QString>::of(&Foo:overloadedFunction)

সংযোজন 3 : আপনি যদি কোনও ওভারলোডেড সিগন্যালের ডকুমেন্টেশনটি দেখে থাকেন তবে এখন ওভারলোডিং সমস্যার সমাধানটি ডক্সে স্পষ্টভাবে বর্ণিত হয়েছে। উদাহরণস্বরূপ, https://doc.qt.io/qt-5/qspinbox.html#valueChanged-1 বলে

দ্রষ্টব্য: সিগন্যাল মান পরিবর্তিত এই শ্রেণিতে ওভারলোড হয়। ফাংশন পয়েন্টার সিনট্যাক্স ব্যবহার করে এই সংকেতটির সাথে সংযোগ স্থাপন করতে, Qt এই উদাহরণে প্রদর্শিত হিসাবে ফাংশন পয়েন্টার প্রাপ্ত করার জন্য একটি সুবিধাজনক সহায়ক সরবরাহ করে:

   connect(spinBox, QOverload<const QString &>::of(&QSpinBox::valueChanged),
[=](const QString &text){ /* ... */ });

1
আহ্ হ্যাঁ, এটি অনেক অর্থবোধ করে। আমি অনুমান করি যে এই জাতীয় ক্ষেত্রে যেখানে সংকেতগুলি / স্লটগুলি অতিরিক্ত বোঝা হয়ে থাকে আমি কেবল পুরানো বাক্য গঠন :-) দিয়ে আটকে থাকব। ধন্যবাদ!
dtruby

17
নতুন সিনট্যাক্স নিয়ে আমি খুব উচ্ছ্বসিত ছিলাম ... এখন হিমশীতল হতাশার শীতল স্প্ল্যাশ।
রাশপিএল

12
যারা ভাবছেন (আমার মতো): "পিএমএফ" মানে "পয়েন্টার টু মেম্বার ফাংশন"।
ভিকি চিজওয়ানি

14
আমি ব্যক্তিগতভাবে static_castপুরানো বাক্য গঠনগুলির চেয়ে কুরুচিকে পছন্দ করি , কেবলমাত্র নতুন সিনট্যাক্সটি সিগন্যাল / স্লটের অস্তিত্বের জন্য একটি সংকলন-সময় পরীক্ষা সক্ষম করে যেখানে পুরানো বাক্য গঠনটি রানটাইম এ ব্যর্থ হয়।
ভিকি চিজওয়ানি

2
দুর্ভাগ্যক্রমে, সংকেত ওভারলোড না করা প্রায়শই একটি বিকল্প নয় — কিউটি প্রায়শই তাদের নিজস্ব সংকেতগুলি ওভারলোড করে। (উদাঃ QSerialPort)
পাইথননট

14

ত্রুটি বার্তাটি হ'ল:

ত্রুটি: কল করার জন্য কোনও মিল নেই function QObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int))

এর গুরুত্বপূর্ণ অংশটি হ'ল " অমীমাংসিত ওভারলোডেড ফাংশন প্রকার " এর উল্লেখ । সংকলকটি আপনার অর্থ QSpinBox::valueChanged(int)বা না তা জানে না QSpinBox::valueChanged(QString)

ওভারলোডটি সমাধানের কয়েকটি উপায় রয়েছে:

  • একটি উপযুক্ত টেম্পলেট পরামিতি সরবরাহ করুন connect()

    QObject::connect<void(QSpinBox::*)(int)>(spinBox, &QSpinBox::valueChanged,
                                             slider,  &QSlider::setValue);
    

    এটি একটি ওভারলোডের connect()সমাধান করতে &QSpinBox::valueChangedবাধ্য করে int

    আপনার যদি স্লট আর্গুমেন্টের জন্য অমীমাংসিত ওভারলোডগুলি থাকে, তবে আপনাকে দ্বিতীয় টেমপ্লেট যুক্তিটি সরবরাহ করতে হবে connect()। দুর্ভাগ্যক্রমে, প্রথম অনুমান করা হবে জিজ্ঞাসা করার জন্য কোন সিনট্যাক্স নেই, তাই আপনাকে উভয় সরবরাহ করতে হবে। দ্বিতীয় পদ্ধতির সাহায্য করতে পারে:

  • সঠিক ধরণের একটি অস্থায়ী পরিবর্তনশীল ব্যবহার করুন

    void(QSpinBox::*signal)(int) = &QSpinBox::valueChanged;
    QObject::connect(spinBox, signal,
                     slider,  &QSlider::setValue);
    

    অ্যাসাইনমেন্টটি signalপছন্দসই ওভারলোডটি নির্বাচন করবে এবং এখন এটি সফলভাবে টেমপ্লেটে প্রতিস্থাপন করা যেতে পারে। এটি 'স্লট' যুক্তির সাথে সমানভাবে ভাল কাজ করে এবং আমি এটি ক্ষেত্রে কম জটিল মনে করি।

  • একটি রূপান্তর ব্যবহার করুন

    আমরা static_castএখানে এড়াতে পারি, কারণ এটি ভাষার সুরক্ষা অপসারণের চেয়ে কেবল একটি জবরদস্তি। আমি এরকম কিছু ব্যবহার করি:

    // Also useful for making the second and
    // third arguments of ?: operator agree.
    template<typename T, typename U> T&& coerce(U&& u) { return u; }
    

    এটি আমাদের লিখতে দেয়

    QObject::connect(spinBox, coerce<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
                     slider, &QSlider::setValue);
    

8

আসলে, আপনি কেবল লাম্বদা এবং এটি দিয়ে আপনার স্লটটি মোড়ানো করতে পারেন:

connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
    slider, &QSlider::setValue);

আরও ভাল চেহারা হবে। : \


0

উপরের সমাধানগুলি কাজ করে, তবে আমি ম্যাক্রো ব্যবহার করে কিছুটা ভিন্ন উপায়ে এটি সমাধান করেছি, সুতরাং কেবল এখানে যদি তা হয়:

#define CONNECTCAST(OBJECT,TYPE,FUNC) static_cast<void(OBJECT::*)(TYPE)>(&OBJECT::FUNC)

এটি আপনার কোডে যুক্ত করুন।

তারপরে, আপনার উদাহরণ:

QObject::connect(spinBox, &QSpinBox::valueChanged,
             slider, &QSlider::setValue);

হয়ে:

QObject::connect(spinBox, CONNECTCAST(QSpinBox, double, valueChanged),
             slider, &QSlider::setValue);

2
সমাধান "উপরে" কি? আপনি বর্তমানে সেগুলি যেভাবে দেখছেন সেভাবে উত্তরগুলি সবার কাছে উপস্থাপন করা হবে বলে মনে করবেন না!
টবি স্পিড

1
একাধিক যুক্তি গ্রহণকারী ওভারলোডগুলির জন্য আপনি কীভাবে এটি ব্যবহার করবেন? কমা সমস্যা সৃষ্টি করে না? আমি মনে করি আপনাকে সত্যিকারের পেরেনগুলি পাস করতে হবে, যেমন #define CONNECTCAST(class,fun,args) static_cast<void(class::*)args>(&class::fun)- CONNECTCAST(QSpinBox, valueChanged, (double))এই ক্ষেত্রে যেমন ব্যবহৃত হয় ।
টবি স্পিড

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.