मैं सीआरटीपी का उपयोग कर बाल वर्ग में उपलब्ध कार्यों के आधार पर आधार वर्गों के कार्यान्वयन को अनुकूलित करने की कोशिश कर रहा हूं।

मैं जो चाहता हूं उसका मूल विचार:

// has_inc_function<Child, void> should detect the presence of a member function void Child::inc()
template<class Child, bool = has_inc_function<Child, void>::value>
struct base
{
    // ... base implementation stuff
};

template<class Child>
struct base<Child, true>
{
    // ... base specialization implementation stuff
};

struct empty : public base<empty>
{};

struct has_inc
{
    void inc()
    {}
};

struct has_inc_and_crtp : public base<has_inc_and_crtp>
{
    void inc()
    {}
};

struct has_inc_and_misuse_crtp : public base<has_inc_and_misuse_crtp, true>
{
    void inc()
    {}
};

struct has_inc_and_misuse_crtp2 : public base<has_inc_and_misuse_crtp, false>
{
    void inc()
    {}
};

struct no_inc_and_misuse_crtp : public base<no_inc_and_misuse_crtp, true>
{
};

int main()
{
    static_assert(has_inc_function<empty, void>::value == false, "");
    static_assert(has_inc_function<has_inc, void>::value == true, "");
    static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");
    static_assert(has_inc_function<has_inc_and_misuse_crtp, void>::value == true, "");
    static_assert(has_inc_function<has_inc_and_misuse_crtp2, void>::value == true, "");
    static_assert(has_inc_function<no_inc_and_misuse_crtp, void>::value == false, "");
}

मैंने has_inc_function<Child, void> के लिए विभिन्न प्रकार के कार्यान्वयन की कोशिश की है, लेकिन वे सभी has_inc_and_crtp के मामले में विफल प्रतीत होते हैं, और मैं इसका पता नहीं लगा सकता। मैंने कंपाइलर एक्सप्लोरर के माध्यम से कई अलग-अलग कंपाइलर्स के साथ परीक्षण किया, और वे सभी एक ही परिणाम देने लगते हैं।

मैं has_inc_function को कैसे कार्यान्वित करूं ताकि यह काम करे जैसा कि मैं इन सभी परीक्षण मामलों में अपेक्षा करता हूं, या जो मैं चाहता हूं वह संभव नहीं है?

कार्यान्वयन मैंने आजमाए हैं

jrok's Solution (कंपाइलर एक्सप्लोरर लिंक):

template <class C, class Ret>
struct has_increment<C, Ret>
{
private:
  template <class T>
  static constexpr auto check(T*) -> typename std::is_same<
    decltype(std::declval<T>().inc()), Ret>::type;

  template <typename> static constexpr std::false_type check(...);

  typedef decltype(check<C>(nullptr)) type;

public:
  static constexpr bool value = type::value;
};

टार्टनलामा का समाधान (कंपाइलर एक्सप्लोरर लिंक):

नोट: वह कार्यान्वयन वापसी प्रकार से मेल नहीं खाता है। मैंने इस काम को C++14 में करने के लिए लाइब्रेरी फंडामेंटल TS v2 में सामान के नमूना कार्यान्वयन को भी शामिल किया है

struct nonesuch
{
  ~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>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;

template <class Default, template<class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;

template<class...> struct disjunction : std::false_type { };
template<class B1> struct disjunction<B1> : B1 { };
template<class B1, class... Bn>
struct disjunction<B1, Bn...> 
    : std::conditional_t<bool(B1::value), B1, disjunction<Bn...>>  { };

template <typename T>
using has_type_t = typename T::inc;

template <typename T>
using has_non_type_t = decltype(&T::inc);

template <typename T, class RetType>
using has_inc_function =
  disjunction<is_detected<has_type_t, T>, is_detected<has_non_type_t, T>>;

वेलेंटिन मिलिया का समाधान ( कंपाइलर एक्सप्लोरर लिंक):

template <class C, class RetType>
class has_inc_function
{
    template <class T>
    static std::true_type testSignature(RetType (T::*)());

    template <class T>
    static decltype(testSignature(&T::inc)) test(std::nullptr_t);

    template <class T>
    static std::false_type test(...);

public:
    using type = decltype(test<C>(nullptr));
    static const bool value = type::value;
};

TTI को बूस्ट करें (मैं कर सका' संकलक एक्सप्लोरर के साथ काम करने के लिए बूस्ट कैसे प्राप्त करें यह पता लगाएं):

#include <boost/tti/has_member_function.hpp>

BOOST_TTI_TRAIT_HAS_MEMBER_FUNCTION(has_inc_function, inc);
2
helloworld922 1 फरवरी 2020, 18:51
लगता है जैसे आप "प्रतिबिंब" चाहते हैं। कौन सी एक विशेषता है C++ में नहीं है।
 – 
Jesper Juhl
1 फरवरी 2020, 19:36
@ जेस्पर जुहल: प्रतिबिंब मदद नहीं करेगा, क्योंकि व्युत्पन्न वर्ग उस बिंदु पर अधूरा है। प्रतिबिंबित करने के लिए कुछ भी नहीं है। आपको इसके बजाय टेम्पलेट मेटाप्रोग्रामिंग चतुराई का उपयोग करना होगा।
 – 
Nicol Bolas
1 फरवरी 2020, 19:37

2 जवाब

सबसे बढ़िया उत्तर

आप जो चाहते हैं वह इस रूप में स्पष्ट रूप से संभव नहीं है। कक्षा के पूर्ण होने से पहले एक वर्ग के माता-पिता को जाना जाता है, और इसलिए इससे पहले कि यह ज्ञात हो कि कक्षा में ऐसा कोई सदस्य कार्य है या नहीं।

आप जो कर सकते हैं वह इस बात पर निर्भर करता है कि आधार की विभिन्न तात्कालिकताएँ कितनी भिन्न हैं। यदि वे मूल रूप से अलग-अलग कार्यान्वयन विवरणों के साथ एक ही इंटरफ़ेस हैं, तो आप एक और वर्ग लिख सकते हैं जिसमें एक ही इंटरफ़ेस और एक भिन्न सदस्य (std::variant दुख की बात है कि सी ++ 17 है, लेकिन आप गतिशील बहुरूपता के साथ भी ऐसा ही कर सकते हैं) जिसमें सभी कॉल्स फॉरवर्ड कर दी जाती हैं। फिर निर्णय जो उपयोग करना है, तत्काल करते समय किया जा सकता है।

आप इस दिशा में भी कुछ प्रयास कर सकते हैं:

#include <type_traits>
#include <iostream>

template<class Child>
struct base {
    int foo();
};

struct has_inc: base<has_inc> {
    void inc();
};

struct has_not_inc: base<has_not_inc> {
};

template<class Child, class = std::void_t<decltype(std::declval<Child>().inc())>>
struct mock {
    int foo(base<Child>*) { return 1;}
};

template<class Child>
struct mock<Child> {
    int foo(base<Child>*) { return 0;}
};

template<class Child>
int base<Child>::foo() {
    return mock<Child,void>().foo(this);
}

int main() {
    has_inc h;
    has_not_inc n;
    std::cout << h.foo() << " " << n.foo() << '\n';
}

यहां आप परिभाषा में केवल प्रकार के पूर्ण बच्चे का उपयोग करते हैं, घोषणा में नहीं। परिभाषा के बिंदु तक, पूरा बच्चा उपलब्ध है, जो कि घोषणा के दौरान नहीं था।

अन्य तरीके भी हैं (मुझे लगता है, सब कुछ इतना आसान नहीं है) और आप जो उपयोग कर सकते हैं वह वास्तव में आपके उपयोग-मामले पर निर्भर करता है, मुझे लगता है।

पुनश्च: std::void_t, C++17 है, लेकिन यह केवल template<class...> using void_t = void; है।

2
n314159 1 फरवरी 2020, 20:49

मैंने has_inc_function<Child, void> के लिए विभिन्न प्रकार के कार्यान्वयन की कोशिश की है, लेकिन वे सभी has_inc_and_crtp के मामले में विफल प्रतीत होते हैं, और मैं इसका पता नहीं लगा सकता।

समस्या (यदि मैं सही ढंग से समझूं) यह है कि, has_inc_and_crpt मामले में, has_inc_function के मान का मूल्यांकन पहले Child के दूसरे टेम्पलेट पैरामीटर के लिए डिफ़ॉल्ट मान निर्धारित करने के लिए किया जाता है।

template<class Child, bool = has_inc_function<Child, void>::value>
struct base 

वह तब होता है जब Child (अर्थात has_inc_and_crpt) अभी भी अधूरा है, इसलिए मान यदि false, और निम्नलिखित उपयोग में है

static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");

false बने रहें।

मैं has_inc_function को कैसे कार्यान्वित करूं ताकि यह काम करे जैसा कि मैं इन सभी परीक्षण मामलों में अपेक्षा करता हूं, या जो मैं चाहता हूं वह संभव नहीं है?

एक त्वरित और गंदा समाधान has_inc_function में एक अतिरिक्त डमी डिफ़ॉल्ट टेम्पलेट पैरामीटर जोड़ा जा सकता है।

उदाहरण द्वारा

// ................................VVVVVVV  dummy and defaulted
template <typename C, typename RT, int = 0>
struct has_inc_function

फिर इसे base में एक विशेष (डिफ़ॉल्ट से अलग) पैरामीटर की व्याख्या करते हुए उपयोग करें

// ........................................................V  different from the default
template<class Child, bool = has_inc_function<Child, void, 1>::value>
struct base 

इसलिए, जब आप has_inc_functin का उपयोग स्थिर जोर में करते हैं,

static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");

वर्ग अलग है, उस क्षण में मूल्यांकन किया जाता है और has_inc_and_crpt का पता inc() विधि से लगाया जाता है।

लेकिन यह केवल परीक्षण मामले (static_assert()) स्तर पर समस्या का समाधान करता है।

अभी भी समस्या बनी हुई है (एक समस्या जिसे मैं हल नहीं कर सकता) कि, base घोषित करते हुए, डिफ़ॉल्ट मान गलत रहता है। तो (मुझे लगता है) has_inc_and_crpt अभी भी गलत base आधार का चयन करें।

Jrok के समाधान के बाद, निम्नलिखित एक पूर्ण संकलन उदाहरण है।

#include <type_traits>

template <typename C, typename RT, int = 0>
struct has_inc_function
 {
   private:
      template <typename T>
      static constexpr auto check(T *) ->
      typename std::is_same<decltype(std::declval<T>().inc()), RT>::type;

      template <typename>
      static constexpr std::false_type check(...);

      using type = decltype(check<C>(nullptr));

   public:
      /// @brief True if there is an inc member function
      static constexpr bool value = type::value;
 };

template <typename Child, bool = has_inc_function<Child, void, 1>::value>
struct base 
 { };

template <typename Child>
struct base<Child, true>
 { };

struct empty : public base<empty>
 { };

struct has_inc
 { void inc() {} };

struct has_inc_and_crtp : public base<has_inc_and_crtp>
 { void inc() {} };

struct has_inc_and_misuse_crtp : public base<has_inc_and_misuse_crtp, true>
 { void inc() {} };

struct has_inc_and_misuse_crtp2 : public base<has_inc_and_misuse_crtp, false>
 { void inc() {} };

struct no_inc_and_misuse_crtp : public base<no_inc_and_misuse_crtp, true>
 { };

template <typename C, typename RT>
constexpr auto hif_v = has_inc_function<C, RT>::value;

int main ()
 {
   static_assert(hif_v<empty, void> == false, "");
   static_assert(hif_v<has_inc, void> == true, "");
   static_assert(hif_v<has_inc_and_crtp, void> == true, "");
   static_assert(hif_v<has_inc_and_misuse_crtp, void> == true, "");
   static_assert(hif_v<has_inc_and_misuse_crtp2, void> == true, "");
   static_assert(hif_v<no_inc_and_misuse_crtp, void> == false, "");
 }
1
max66 1 फरवरी 2020, 21:04