2016-09-27 4 views
12

मैं संकलन-समय पर जांचना चाहता हूं यदि उपयोगकर्ता शाब्दिक _nameRet प्रकार और तर्क Arg के लिए परिभाषित किया गया है। जब मैं आधा समाधान है, यह शाब्दिक operator की आवश्यकता कम से कम एक बार में परिभाषित किया जा करने के लिए:क्या यह जांचना संभव है कि उपयोगकर्ता शब्द को दिए गए प्रकार और तर्क के लिए परिभाषित किया गया है या नहीं?

#include <iostream> 
#include <type_traits> 

struct one { }; 
struct two { }; 

// we need at least one of these definitions for template below to compile 
one operator"" _x(char const*) {return {};} 
two operator"" _x(unsigned long long int) {return {};} 

template<class T, class S, class = void> 
struct has_literal_x : std::false_type 
{ }; 

template<class T, class S> 
struct has_literal_x <T, S, 
    std::void_t<decltype((T(*)(S))(operator"" _x))> 
    > : std::true_type 
{ }; 

int main() 
{ 
    std::cout << has_literal_x<one, char const*>::value << std::endl; 
    std::cout << has_literal_x<two, unsigned long long int>::value << std::endl; 

    std::cout << has_literal_x<one, unsigned long long int>::value << std::endl; 
    std::cout << has_literal_x<two, char const*>::value << std::endl; 

    std::cout << has_literal_x<int, char const*>::value << std::endl; 
} 

आउटपुट:

1 
1 
0 
0 
0 

लेकिन अगर संभवतः अतिभारित उपयोगकर्ता शाब्दिक कम से कम एक परिभाषा नहीं है , यह समाधान काम नहीं करेगा। क्या गैर-मौजूदा अक्षरों के लिए भी इसे जांचने का कोई तरीका है (संभवतः उसी तरह हम जांच सकते हैं कि कक्षा X में सदस्य member है, लेकिन मुझे नहीं पता कि यह इस मामले में व्यवहार्य है या नहीं)?

उत्तर

9

क्या यह जांचना संभव है कि उपयोगकर्ता शब्द को दिए गए प्रकार और तर्क के लिए परिभाषित किया गया है या नहीं?

(संक्षिप्त) उत्तर हाँ है।


एक उदाहरण के रूप में, आप अपने उदाहरण कोड में निम्नलिखित विशेषज्ञता का उपयोग कर सकते हैं:

template<class T, class S> 
struct has_literal_x <T, S, 
     std::enable_if_t<std::is_same<decltype(operator""_x(std::declval<S>())), T>::value> 
    > : std::true_type 
{ }; 

कि जल्दी से हो जाता है: सभी के लिए 0:

#include <iostream> 
#include <type_traits> 
#include <utility> 

struct one { }; 
struct two { }; 

//one operator"" _x(char const*) { return {}; } 
//two operator"" _x(unsigned long long int) { return {}; } 

template<class T, class S, class = void> 
struct has_literal_x : std::false_type 
{ }; 

template<class T, class S> 
struct has_literal_x <T, S, 
     std::enable_if_t<std::is_same<decltype(operator""_x(std::declval<S>())), T>::value> 
    > : std::true_type 
{ }; 

int main() 
{ 
    std::cout << has_literal_x<one, char const*>::value << std::endl; 
    std::cout << has_literal_x<two, unsigned long long int>::value << std::endl; 

    std::cout << has_literal_x<one, unsigned long long int>::value << std::endl; 
    std::cout << has_literal_x<two, char const*>::value << std::endl; 

    std::cout << has_literal_x<int, char const*>::value << std::endl; 
} 

उत्पादन की उम्मीद है एक उनमें से।


एक और तरीका है कि ऐसा करने के लिए सी ++ 14 (ज्यादातर @ Jarod42 की this जवाब से प्रेरित) एक टेम्पलेट चर के माध्यम से है।
एक उदाहरण के रूप:

template<typename T, typename S, typename = void> 
constexpr bool has_literal_v = false; 

template<typename T, typename S> 
constexpr bool has_literal_v<T, S, std::enable_if_t<std::is_same<decltype(operator""_x(std::declval<S>())), T>::value>> = true; 

main बजाय बन जाएगा:

int main() 
{ 
    std::cout << has_literal_v<one, char const*> << std::endl; 
    std::cout << has_literal_v<two, unsigned long long int> << std::endl; 

    std::cout << has_literal_v<one, unsigned long long int> << std::endl; 
    std::cout << has_literal_v<two, char const*> << std::endl; 

    std::cout << has_literal_v<int, char const*> << std::endl; 
} 

मैं इसे आसान को पढ़ने के लिए और है कि एक constexpr चर है पाते हैं। और क्या?

+0

नोट यह परीक्षण कर सकते हैं इस समाधान नहीं करता है काफी काम करता है, तो ऑपरेटर प्रकार के बाद परिभाषित किया गया है विशेषता कम से कम जीसीसी में परिभाषित की गई है: http://coliru.stacked-crooked.com/a/6f70eb6cbf236473 – xinaiz

5
is_detected कार्यों परिवार के साथ

, तो आप सिर्फ

template <typename T> 
using has_literal_x_type = decltype(operator"" _x(std::declval<T>())); 

template <typename Ret, typename T> 
using has_literal_x = std::is_same<Ret, detected_t<has_literal_x_type, T>>; 

करना और साथ

static_assert(!has_literal_x<one, char const*>::value, "unexpected"); 
static_assert(!has_literal_x<one, unsigned long long int>::value, "unexpected"); 
static_assert(!has_literal_x<two, char const*>::value, "unexpected"); 
static_assert(!has_literal_x<two, unsigned long long int>::value, "unexpected"); 
static_assert(!has_literal_x<int, char const*>::value, "unexpected"); 

Demo

+1

यह 'std :: declvalनहीं होना चाहिए() '' std :: declval 'के बजाय'? – skypjack

+1

@skypjack: निश्चित, निश्चित, धन्यवाद। मैं डेमो में वैध केस नहीं जोड़ना चाहता था क्योंकि ओपी उम्मीद करता था कि ऑपरेटर प्रकट नहीं हो सकता है, इसलिए मुझे लगता है कि टाइपो ... – Jarod42

+1

अच्छा, यह जानवर है!सामान्य शब्दों में बढ़िया समाधान, लेकिन मुझे किसी भी कामकाजी समाधान की उम्मीद थी, और स्काईपैक इस बार पहली बार था और इसे आम तौर पर ज्ञात वाक्यविन्यास के साथ किया गया था :) हालांकि 'is_detected' प्रश्न का विजेता होगा "जटिल SFINAE वाक्यविन्यास को सरल कैसे करें"। – xinaiz

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

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