2016-09-11 5 views
6

को देखते हुए 2 प्रकार T और U मैं चाहे वह वस्तुओं के लिए उन (यानी के बीच operator * कॉल करने के लिए संभव है पता लगाने के लिए चाहते हैं यह संभव t * u लिखने के लिए जहां t प्रकार T की है और u प्रकार U)(पर विचार static_asserts) का पता लगाने के लिए कि क्या ऑपरेटर मौजूद है और ग में प्रतिदेय ++

मैं c++ detection idiom उपयोग कर रहा हूँ की है, लेकिन यह अभी तक अपने संकलक में उपलब्ध नहीं है के बाद से मैं इसे अपने आप की तरह इस

struct nonesuch { 
    nonesuch() = delete; 
    ~nonesuch() = delete; 
    nonesuch(nonesuch const&) = delete; 
    void operator=(nonesuch const&) = delete; 
}; 

namespace detail { 
template <class Default, class AlwaysVoid, template<class...> class Op, class... Args> 
struct detector { 
    using value_t = std::false_type; 
    using type = Default; 
}; 

template <class Default, template<class...> class Op, class... Args> 
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> { 
    using value_t = std::true_type; 
    using type = Op<Args...>; 
}; 

} // namespace detail 

template <template<class...> class Op, class... Args> 
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t; 

template< template<class...> class Op, class... Args > 
constexpr bool is_detected_v = is_detected<Op, Args...>::value; 

नहीं लागू किया डब्ल्यू मैं ऐसे सहायक है:

template <typename T, typename U> 
using multiply = decltype(std::declval<T>() * std::declval<U>()); 

और पता लगाने के लिए कि क्या यह प्रतिदेय है मैं फोन

bool can_multiply = is_detected_v<multiply, T, U> 

यह लगभग ठीक, उदाहरण के लिए इस प्रिंट है 1, उम्मीद 0 के रूप में

std::cout << is_detected_v<multiply, int, int> << std::endl; 
std::cout << is_detected_v<multiply, std::vector<int>, std::vector<int>> << std::endl; 

लेकिन अब मेरे पास कक्षा

template<typename T> 
class A { 
}; 

template<typename T> 
A<T> operator*(const A<T>&, const A<T>&) { 
    static_assert(!std::is_same<bool, T>::value); 
    return A<T>(); 
} 

यहां A<bool>A<bool> से गुणा नहीं किया जा सकता, लेकिन मेरे कोड का पता लगाता है कि यह संभव है

std::cout << is_detected_v<multiply, A<bool>, A<bool>> << std::endl; // 1 
A<bool>() * A<bool>(); // does't compile 

तो, मेरे सवाल, कैसे मेरे कोड तरीकों का पता नहीं लगा करने के लिए तय करने के लिए किया जाता है, जब वे बाहर static_asserted? मुझे लगता है कि मैं कुछ sfinae के साथ static_assert को प्रतिस्थापित कर सकता हूं लेकिन मैं नहीं चाहता (क्योंकि मेरे पास पहुंच नहीं है और static_asserts के अलावा बेहतर त्रुटि संदेश हैं)।

उत्तर

7

तो, मेरे सवाल, कैसे मेरे कोड तरीकों का पता नहीं लगा करने के लिए तय करने के लिए किया जाता है, जब वे बाहर static_asserted?

आप बस नहीं कर सकते हैं। यह static_assert के डाउनसाइड्स में से एक है - किसी ऑपरेशन की वैधता को बाहरी रूप से सत्यापित करने का कोई तरीका नहीं है। ऐसा इसलिए है क्योंकि static_assertoperator* के तत्कालता के "तत्काल संदर्भ" में नहीं होता है, और इसलिए SFINAE लागू नहीं होता है - यह हमेशा एक कठिन त्रुटि होगी।

मुझे लगता है कि मैं कुछ sfinae के साथ static_assert को प्रतिस्थापित कर सकता हूं लेकिन मैं नहीं चाहता (क्योंकि मेरे पास पहुंच नहीं है और static_asserts के अलावा बेहतर त्रुटि संदेश हैं)।

मैं सहानुभूति व्यक्त करता हूं। लेकिन यह मूल रूप से व्यापार बंद है। SFINAE और प्रकार की जांच, या static_assert और स्पष्ट त्रुटियां। (निश्चित रूप से इस मामले में आप केवल एक गैर-टेम्पलेट A<bool> operator*(A<bool> const&, A<bool> const&) लिख सकते हैं लेकिन शायद यह बिंदु के अलावा)।

+0

समझाते हुए क्यों मदद मिल सकती है (एसएफआईएनएई जांच अधिभार रिज़ॉल्यूशन के दौरान की जानी चाहिए; हर कंपाइलर को संकलित करने के लिए प्रत्येक कंपाइलर को मजबूर करना और यह निर्धारित करने से पहले कि क्या ओवरलोड लोड है, दोनों संकलक लेखकों के लिए कठिन होगा, और परिणाम हो सकता है आश्चर्यजनक व्यवहार में (मैंने 'शून्य *' को 'टी *' से अधिक पसंद किया क्योंकि आपके 'टी *' कोड में एक बग है जिसमें कोड 2 स्तरों में गहरा घोंसला गलती है)। SFINAE चेक एक समझौता है, और यहां तक ​​कि एमएसवीसी भी उन पर * हार्ड * गिर जाता है। – Yakk

संबंधित मुद्दे