2012-09-27 19 views
9

मैं के लिए सी ++ 11 enable_if के निम्न उदाहरण देखा:C++ 11 enable_if त्रुटि

struct is_64_bit 
{ 
    static const bool value = sizeof(void*) == 8; 
}; 

enable_if<is_64_bit::value, void>::type 
my_memcpy(void* target, const void* source, size_t n) 
{ 
    cout << "64 bit memcpy" << endl; 
} 

enable_if<!is_64_bit::value, void>::type 
my_memcpy(void* target, const void* source, size_t n) 
{ 
    cout << "32 bit memcpy" << endl; 
} 

मैं समझता हूँ के रूप में, प्रणाली वास्तुकला के आधार पर, "my_memcpy" समारोह उपलब्ध या तो 32 के लिए किया जाएगा या 64 बिट संस्करण। लेकिन मैं संकलन पर निम्न त्रुटि हो रही है:

error: ‘type’ in ‘struct std::enable_if<false, void>’ does not name a type 

मैं थोड़ा उलझन में हूं, क्योंकि मैंने सोचा था कि केवल 32 संस्करण उपलब्ध होना चाहिए (मैं लिनक्स फेडोरा 32 बिट का उपयोग कर रहा)।

शायद इस उदाहरण के साथ कुछ गलत है? या क्या मैं कुछ न कुछ भूल रहा हूं?

धन्यवाद।

उत्तर

9

टेम्पलेट template< bool B, class T = void > struct enable_if विशिष्ट है ताकि यह केवल typedef type हो जब स्थिति बी true हो।

आपका कंपाइलर सही है। struct std::enable_if<false, void> में type के लिए कोई टाइपिफ़ नहीं है। struct std::enable_if<true, void> में केवल एक टाइपिफ़ है।

अधिक जानकारी के लिए here देखें।

इसलिए अपनी समस्या को ठीक करने के लिए आपको यह सुनिश्चित करने की आवश्यकता है कि enable_if जिसमें बी 12 है जो false का मूल्यांकन कभी संकलित नहीं होता है। my_memcpy एक फ़ंक्शन टेम्पलेट बनाकर आप SFINAE की सहायता से इसे प्राप्त कर सकते हैं। संकलक तब फ़ंक्शन टेम्पलेट को संकलित करने में विफल होने पर त्रुटि की रिपोर्ट नहीं करेगा, जहां बी false पर मूल्यांकन करता है और सफलतापूर्वक संकलित और उस फ़ंक्शन का उपयोग करेगा जहां बी true का मूल्यांकन करता है।

#include <iostream> 
#include <type_traits> 

using namespace std; 


struct is_64_bit 
{ 
    static const bool value = sizeof(void*) == 8; 
}; 

template<typename T> 
typename enable_if<is_64_bit::value, T>::type 
my_memcpy(T* target, const T* source, size_t n) 
{ 
    cout << "64 bit memcpy" << endl; 
} 

template<typename T> 
typename enable_if<!is_64_bit::value, T>::type 
my_memcpy(T* target, const T* source, size_t n) 
{ 
    cout << "32 bit memcpy" << endl; 
} 
+0

धन्यवाद Cyon। यह अभी हल हो गया है। इसके अलावा मुझे इस विषय की बेहतर समझ है। :) – user1274605

10

std::enable_ifsubstitution failure is not an error के सिद्धांत (SFINAE) है, जो कहता है कि जब त्रुटि के कुछ प्रकार के एक समारोह टेम्पलेट instantiating में पाए जाते हैं, प्रोग्राम है जो समारोह टेम्पलेट अधिभार संकल्प में भाग नहीं ले के साथ संकलित करने के लिए जारी है के माध्यम से काम करता है।

एसएफआईएनएई के लिए किक करने के लिए, (ए) इसे किसी फ़ंक्शन (या विधि) टेम्पलेट पर उपयोग किया जाना चाहिए और (बी) इसे टेम्पलेट पैरामीटर पर निर्भर होना चाहिए। आपका कार्यक्रम दोनों मायने रखता है।

टेम्पलेट पैरामीटर पर enable_if निर्भर बनाने के लिए, सबसे आसान काम एक डिफ़ॉल्ट पैरामीटर जोड़ने के लिए है:

template<typename T = void> typename enable_if<is_64_bit::value, T>::type 
my_memcpy(void* target, const void* source, size_t n) 

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

#include <iostream> 

template<int = sizeof(void *)> void my_memcpy(void* target, const void* source, size_t n); 

template<> void my_memcpy<8>(void* target, const void* source, size_t n) { 
    std::cout << "64 bit memcpy" << std::endl; 
} 

template<> void my_memcpy<4>(void* target, const void* source, size_t n) { 
    std::cout << "32 bit memcpy" << std::endl; 
} 
+0

+1 के लिए "SFINAE को लात मारने के लिए, (ए) इसे फ़ंक्शन (या विधि) टेम्पलेट पर उपयोग किया जाना चाहिए और (बी) इसे टेम्पलेट पैरामीटर पर निर्भर होना चाहिए।" अब मैं वास्तव में इसे प्राप्त करता हूँ। – Claudiu

3

SFINAE टेम्पलेट्स के लिए है। क्या आप की जरूरत टेम्पलेट का उपयोग करने के लिए, अन्य उत्तर उल्लेख किया है, या सिर्फ एक संकलन समय शाखा है, जो IMO अधिक उपयुक्त समाधान (बजाय एक अनावश्यक टेम्पलेट परिचय) है:

struct is_64_bit : 
    std::integral_constant<bool, sizeof(void*) == 8> 
{}; 

namespace detail 
{ 
    void my_memcpy(void* target, const void* source, std::size_t n, std::true_type) 
    { 
     std::cout << "64 bit memcpy" << std::endl; 
    } 


    void my_memcpy(void* target, const void* source, std::size_t n, std::false_type) 
    { 
     std::cout << "32 bit memcpy" << std::endl; 
    } 
} 

void my_memcpy(void* target, const void* source, std::size_t n) 
{ 
    my_memcpy(target, source, n, is_64_bit()); 
} 
संबंधित मुद्दे