टेम्प्लेट का उपयोग करके फ़ंक्शन को ओवरलोड करना


34

मैं टेम्प्लेट का उपयोग करके फ़ंक्शन को परिभाषित करने की कोशिश कर रहा हूं और मैं चाहता हूं कि टाइपनेम या तो इंट या एनीम (एक विशिष्ट एनम जिसे मैंने परिभाषित किया था) हो। मैंने निम्नलिखित कोशिश की है लेकिन मैं असफल रहा हूँ:

template <int | anEnum T> // or <int T, anEnum T> or <int, anEnum T>
bool isFunction(const T &aVariable){}

मैं जो करने की कोशिश कर रहा हूं वह दो अतिभारित कार्यों को परिभाषित करने के बजाय टेम्प्लेट का उपयोग करना है। मैं प्रोग्रामर को निम्नलिखित के रूप में बुलाया जाना पसंद करता हूं, प्रोग्रामर के बिना प्रकार पर विचार करने के लिए

isFunction(aVariable) // and not isFunction<int> (aVariable) nor isFunction<anEnum> (aVariable)

मूल रूप से, मैं चाहता हूं कि इस फ़ंक्शन को int और Num प्रकारों के लिए अस्थायी किया जाए। मैंने इसके लिए खोज की है, लेकिन जवाब नहीं मिला। मुझे क्या याद आ रही है? धन्यवाद,


यदि यह वास्तव में एकल एनम या टाइप इंट है, तो बस दोनों फ़ंक्शन क्यों नहीं लिखें? आपको उस मामले में टेम्पलेट की आवश्यकता क्यों है?
क्लॉस

अन्य प्रकारों के बारे में क्या? क्या आप falseअन्य प्रकारों के लिए लौटना चाहते हैं या अन्य प्रकारों के लिए फ़ंक्शन को तुरंत नहीं करना चाहते हैं।
मेंढक

@frogatto नहीं, बूल रिटर्न वैल्यू में कुछ भी प्रकार नहीं है।
bg

@Klaus मैंने विकल्प सीखने के लिए कहा है। वर्तमान उत्तरों के आधार पर, मैंने दोनों कार्यों को बस परिभाषित करने का निर्णय लिया है।
bg

जवाबों:


25

गैर-सी ++ 20 उत्तर के अलावा, यदि आप किसी भी तरह से, सी ++ 20 और इसकी conceptsविशेषता का उपयोग करने में सक्षम हैं, तो मैं आपको निम्नलिखित कार्यान्वयन का सुझाव दूंगा :

#include <iostream>
#include <concepts>

enum class MyEnum {
    A,
    B,
    C
};

template <typename T>
concept IntegralOrEnum = std::same_as<MyEnum, T> || std::integral<T>;

template <IntegralOrEnum T>
bool isFunction(T const& aVariable) {
    return true;
}

int main() {
    isFunction(MyEnum::A);
    isFunction(3);
    isFunction("my_string"); // error
    return 0;
}

डेमो

अपडेट करें

@RichardSmith की टिप्पणी के अनुसार , यहाँ एक और अधिक स्केलेबल और पुन: प्रयोज्य दृष्टिकोण है:

template <typename T, typename ...U>
concept one_of = (std::is_same_v<T, U> || ...);

template <one_of<int, MyEnum> T>
bool isFunction(T const& aVariable) {
    return true;
}

दो विशिष्ट प्रकारों में से एक के प्रकार की आवश्यकता के विशिष्ट मामले के लिए, ऐसा कुछ बेहतर काम कर सकता है: template<typename T, typename ...U> concept one_of = (std::is_same_v<T, U> || ...); template<one_of<int, MyEnum> T> bool isFunction(T const& aVariable) {
रिचर्ड स्मिथ

1
@RichardSmith मैंने उसी के साथ अपना उत्तर भी अपडेट किया है। मुझे यह अधिक पुन: प्रयोज्य और स्केलेबल लगता है। धन्यवाद
सरौता

21

इसे पूरा करने के कुछ तरीके हैं। सभी type_traitsहेडर का उपयोग करना शामिल है । आप उदाहरण के लिए, फ़ंक्शन के मुख्य भाग में मौजूद प्रश्न के प्रकारों पर स्थिर दावा कर सकते हैं।

या, यदि आपको अन्य ओवरलोड के बीच इस फ़ंक्शन पर विचार करने की आवश्यकता है, तो एक SFINAE तकनीक को नियोजित किया जा सकता है।

template<typename T>
auto isFunction(const T &aVariable) 
  -> std::enable_if_t<std::is_same<T, int>::value || std::is_same<T,anEnum>::value, bool> {
}

यह फ़ंक्शन ओवरलोड सेट से फ़ंक्शन को हटा देगा, अगर यह कहा जाता है कि क्या प्रकार मेल नहीं खाते हैं। लेकिन अगर आपको इस व्यवहार की आवश्यकता नहीं है, तो एक स्थैतिक दावा एक अधिक प्रोग्रामर अनुकूल त्रुटि संदेश के लिए अनुमति देता है।


3

इस समाधान के बारे में क्या? फ़ंक्शन के साथ एक कोड संकलित किया जाएगा यदि टाइप टी आपके अनुरोधों को संतुष्ट करता है। अन्यथा, स्थैतिक दावा विफल रहा।

#include <type_traits>
enum anEnum {
    //
};

template <typename T, bool defined = std::is_same<T, int>::value ||
                                     std::is_same<T, anEnum>::value>
bool isFunction(const T& aVariable)
{
    static_assert(defined, "Invalid specialization");

    bool result = false;
    // Put your code here
    return result;
}

1
यदि अन्य हस्ताक्षर मौजूद हैं (जैसे एक काल्पनिक isFunction(std::string_view)) , तो यह अधिभार संकल्प के साथ अच्छी तरह से काम नहीं करता है । हस्ताक्षर अभी भी एक वैध मिलान होगा, लेकिन तात्कालिकता त्रुटि का कारण बनती है।
LF

आप बेकार हस्ताक्षरों को हटाए जाने की घोषणा कर सकते हैं: bool isFunction (std :: string_view) = delete;
ixjxk

मैं अतिरिक्त अधिभार के बारे में बात कर रहा हूँ। उस स्थिति में, यह अमान्य हस्ताक्षर एक सटीक मिलान (जैसे, स्ट्रिंग शाब्दिक के लिए) हो सकता है, इस प्रकार अधिभार को अवरुद्ध कर सकता है।
LF

0

मैंने https://stackoverflow.com/a/60271100/12894563 उत्तर में सुधार किया है । यदि इस स्थिति में मदद कर सकता है:

template <typename T>
struct always_false : std::false_type {};

template <typename T>
bool isFunction(const T& aVariable)
{
    if constexpr(std::is_same_v<T, int> || std::is_same_v<T, anEnum>)
    {
        std::cout << "int\n";
        // put your code here
        return true;
    }
    else
    {
        static_assert(always_false<T>::value, "You should declare non-template function or write if constexpr branch for your type");
        return false;
    }
}

bool isFunction(std::string_view)
{
    std::cout << "std::string_view\n";
    return true;
}

int main()
{
    isFunction(std::string_view("1L"));
    isFunction(1);
    //isFunction(1L); // will produce an error message from static_assert
}

isFunction (1L) विफल हो जाएगा क्योंकि कोई अतिभारित फ़ंक्शन या 'यदि कॉन्स्ट्रेक्स' शाखा नहीं है।

अद्यतन: निश्चित याद किया

template <typename T>
struct always_false : std::false_type {};

https://godbolt.org/z/eh4pVn


static_assert(false, ...)बिना उपयोग किए बिना भी बीमार एनडीआर का गठन किया जाता है। यदि आप भाग्यशाली हैं, तो आपका कंपाइलर आपको तुरंत बता देगा, जैसे कि क्लैंग
StoryTeller - अनसलैंडर मोनिका

आपकी टिप्पणी के लिए बहुत बहुत धन्यवाद, मैंने एक गलती की। फिक्स्ड, godbolt.org/z/eh4pVn
ixjxk
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.