ফাংশন সংজ্ঞায়িত কেবল সেই ধরণের জন্য ফাংশন টেম্পলেটের ভিতরে ফাংশন কার্যকর করুন


13

আমার কাছে একটি ফাংশন টেম্পলেট রয়েছে যা এটি বিভিন্ন ইনপুট হিসাবে বিভিন্ন ধরণের নেয়। এই ধরণেরগুলির মধ্যে কেবল একটির getInt()ফাংশন রয়েছে। সুতরাং আমি চাই কোডটি কেবল সেই ধরণের জন্য ফাংশনটি চালানো হোক। একটি সমাধান পরামর্শ দিন। ধন্যবাদ

#include <type_traits>
#include <typeinfo>

class X {
    public:
    int getInt(){
        return 9;
    }
};

class Y{

};

template<typename T>
void f(T& v){
    // error: 'class Y' has no member named 'getInt'
    // also tried std::is_same<T, X>::value 
    if(typeid(T).name() == typeid(X).name()){
        int i = v.getInt();// I want this to be called for X only
    }
}

int main(){
    Y y;
    f(y);
}

আপনার সমস্যার সাথে সম্পর্কিত নয়, তবে type_infoকাঠামোর একটি সমতা তুলনা অপারেটর রয়েছে , তাই typeid(T) == typeid(X)পাশাপাশি কাজ করা উচিত।
কিছু প্রোগ্রামার ড্যুডে

5
ব্যবহার করুন: if constexprশর্ত সহ is_same_v<T,X>
rafix07

এর সমাধানটি এই বছরের শেষের দিকে ধারণাগুলির সাথে আরও মার্জিত হয়ে উঠবে। এখনই সুপার সহায়ক নয়, আমি জানি।
মধ্যমতা

আপনার সমস্যা সমাধানের বিভিন্ন উপায় রয়েছে are উপরে উল্লিখিত একটি দম্পতি কোনও প্রকারের কলযোগ্য সদস্য আছে কিনা তা দেখতে আপনি বিভিন্ন রূপের বৈশিষ্ট্যও ব্যবহার করতে পারেন getInt। স্ট্যাকওভারফ্লো ডটকম-এ একা এখানে অবশ্যই বেশ কয়েকটি প্রশ্ন থাকতে হবে যে কীভাবে কোনও কাঠামো বা শ্রেণীর একটি নির্দিষ্ট সদস্যের কার্যকারিতা রয়েছে কিনা তা দেখার জন্য, আপনি যদি কেবল একটু অনুসন্ধান করেন।
কিছু প্রোগ্রামার ড্যুডে

উত্তর:


10

আপনি যদি না কেবল fফাংশন সদস্য রয়েছে এমন সমস্ত প্রকারের জন্য একটি ফাংশন কল করতে সক্ষম হতে চান তবে আপনি ফাংশনের জন্য ২ টি ওভারলোড ঘোষণা করতে পারেন :getIntXf

  1. getIntশ্রেণীর সহ সদস্য ফাংশন রয়েছে এমন ধরণের জন্যX

  2. ক্লাস সহ অন্যান্য সমস্ত ধরণের জন্য Y

সি ++ 11 / সি ++ 17 সমাধান

এটি মনে রেখে আপনি এই জাতীয় কিছু করতে পারেন:

#include <iostream>
#include <type_traits>

template <typename, typename = void>
struct has_getInt : std::false_type {};

template <typename T>
struct has_getInt<T, std::void_t<decltype(((T*)nullptr)->getInt())>> : std::is_convertible<decltype(((T*)nullptr)->getInt()), int>
{};

class X {
public:
    int getInt(){
        return 9;
    }
};

class Y {};

template <typename T,
          typename std::enable_if<!has_getInt<T>::value, T>::type* = nullptr>
void f(T& v) {
    // only for Y
    std::cout << "Y" << std::endl;
}

template <typename T,
          typename std::enable_if<has_getInt<T>::value, T>::type* = nullptr>
void f(T& v){
    // only for X
    int i = v.getInt();
    std::cout << "X" << std::endl;
}

int main() {
    X x;
    f(x);

    Y y;
    f(y);
}

এটি সরাসরি দেখুন

দয়া করে নোট করুন যেটি std::void_tসি ++ 17 এ প্রবর্তিত হয়েছে, তবে আপনি যদি সি ++ 11 এর মধ্যে সীমাবদ্ধ থাকেন তবে void_tআপনার নিজের থেকে বাস্তবায়ন করা সত্যিই সহজ :

template <typename...>
using void_t = void;

এবং এখানে সি ++ 11 সংস্করণ লাইভ

আমাদের C ++ 20 এ কী আছে?

সি ++ ২০ টি প্রচুর ভাল জিনিস নিয়ে আসে এবং এর মধ্যে একটি ধারণা । C ++ 11 / C ++ 14 / C ++ 17 এর জন্য বৈধ যে জিনিসটি সি ++ 20 তে উল্লেখযোগ্যভাবে হ্রাস করা যেতে পারে:

#include <iostream>
#include <concepts>

template<typename T>
concept HasGetInt = requires (T& v) { { v.getInt() } -> std::convertible_to<int>; };

class X {
public:
    int getInt(){
        return 9;
    }
};

class Y {};

template <typename T>
void f(T& v) {
    // only for Y
    std::cout << "Y" << std::endl;
}

template <HasGetInt T>
void f(T& v){
    // only for X
    int i = v.getInt();
    std::cout << "X" << std::endl;
}

int main() {
    X x;
    f(x);

    Y y;
    f(y);
}

এটি সরাসরি দেখুন


সি ++ ১ to এর পূর্বে, সেই বাস্তবায়ন void_tকিছু পুরানো সংকলককে সমস্যা তৈরি করে যদিও (লিঙ্কটি দ্বারা নির্দেশিত)।
জারোড 42

দুটি ওভারলোড লিখতে কঠোরভাবে প্রয়োজন হয় না ("
ক্যান

@ idclev463035818 আপডেট হয়েছে। ধন্যবাদ
নটক্র্যাকার

1
@ এসএএন আপডেট হয়েছে
নিউটক্র্যাকার

1
ধারণা সংজ্ঞা সঠিক নয়। আপনি রেজাল্টটি একটি ইনটকে অর্পণ করছেন যাতে ধারণাটি হওয়া উচিতtemplate<typename T> concept HasGetInt = requires (T& v) { {v.getInt()} -> std::convertible_to<int>; };
হুই

8

আপনি if constexprসি ++ 17 থেকে ব্যবহার করতে পারেন :

template<typename T>
void f(T& v){
    if constexpr(std::is_same_v<T, X>) { // Or better create trait has_getInt
        int i = v.getInt();// I want this to be called for X only
    }
    // ...
}

এর আগে, আপনাকে ওভারলোড এবং SFINAE বা ট্যাগ প্রেরণ করতে হবে।


if constexprএকটি সি ++ 17 বৈশিষ্ট্য।
আন্দ্রে সেমাসেভ

তবে এটি কেবল শ্রেণীর জন্য কাজ করবেX
নটক্র্যাকার

প্রশ্নটি এখন কেবল সি ++ 11 / সি ++ 14- এ আপডেট করা হয়েছে
নটক্র্যাকার

@ নটক্র্যাকার: ট্যাগ / প্রশ্ন আপডেট করা ভাল নয় এবং তাই বিদ্যমান উত্তরগুলি অকার্যকর করে দিচ্ছে ... (এমনকি যদি সে সম্পর্কে সতর্কতাও ঠিক থাকে তবে)।
জারোদ 42

আমি সবেমাত্র ট্যাগ আপডেট করেছি ... প্রশ্নের শিরোনাম ওপি দ্বারা আপডেট করা হয়েছিল
নটক্র্যাকার

7

এটি সহজ এবং ওভারলোড রাখুন। কমপক্ষে সি ++ 98 সাল থেকে কাজ করেছে ...

template<typename T>
void f(T& v)
{
    // do whatever
}

void f(X& v)
{
    int result = v.getInt();
}

যদি getIntফাংশন সহ কেবল কখনও এক ধরণের থাকে তবে এটি যথেষ্ট । যদি আরও কিছু থাকে তবে এটি এত সহজ নয়। এটি করার বিভিন্ন উপায় রয়েছে, এখানে একটি:

struct PriorityA { };
struct PriorityB : PriorityA { };

template<typename T>
void f_impl(T& t, PriorityA)
{
    // generic version
}

// use expression SFINAE (-> decltype part)
// to enable/disable this overload
template<typename T>
auto f_impl(T& t, PriorityB) -> decltype(t.getInt(), void())
{
    t.getInt();
}

template<typename T>
void f(T& t)
{
    f_impl(t, PriorityB{ } ); // this will select PriorityB overload if it exists in overload set
                              // otherwise PriorityB gets sliced to PriorityA and calls generic version
}

ডায়াগনস্টিক আউটপুট সহ লাইভ উদাহরণ।


1
এক্ষেত্রে এটি কাজ করবে যেহেতু কেবলমাত্র একটি ওভারলোড (জন্য X) রয়েছে, তবে, যদি getIntভবিষ্যতে সদস্যের সাথে অনুরূপ আরও কিছু থাকে তবে এটি এত ভাল অনুশীলন নয়। আপনি সম্ভবত এটি নোট করতে চান
নটক্র্যাকার

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