फिलहाल, मेरे पास नीचे काम करने वाला कोड है जहां कक्षा X का उपयोग करते हुए, मैं कई वर्गों के लिए एक सामान्य इंटरफ़ेस प्रदान करता हूं - मैं केवल एक स्थिर f फ़ंक्शन मौजूद होने की अपेक्षा करता हूं, लेकिन न ही मैं रिटर्न को ठीक करता हूं प्रकार और न ही पैरामीटर:

#include <iostream>
#include <type_traits>

class A {
public:
  static void f()
  {
    std::cout << "A::f()" << std::endl;
  }
};

class B {
public:
  static size_t f(std::string const& s_)
  {
    std::cout << "B::f()" << std::endl;
    return s_.size();
  }
};

class C {
};


template <typename T>
class X {
public:
  static
  void
  f(...)
  {
    std::cout << "Operation not supported!" << std::endl;
  }

  template <typename... Args>
  static
  std::result_of_t<decltype(&T::f)(Args...)>
  f(Args&&... args_)
  {
    return T::f(std::forward<Args>(args_)...);
  }
};

int main()
{
  X<A>::f();  // Compiles, but unexpected overload!
  auto const x = X<B>::f("Hello");  // Works just fine
  std::cout << x << std::endl;
//  X<C>::f();  // Does NOT compile!
  return 0;
}

हालाँकि, मुझे इसके साथ कई समस्याएं हैं (जैसा कि टिप्पणियों में ऊपर चिह्नित किया गया है):

  1. अगर मैं फ़ंक्शन को उपस्थित नहीं होने देता और लाइन को असम्बद्ध करता हूं C को टेम्पलेट पैरामीटर के रूप में उपयोग करते हुए, कोड संकलित नहीं होता है, यह अभी भी C के एक फंक्शन f की अपेक्षा करता है:

    In instantiation of ‘class X<C>’:
    required from here
    error: ‘f’ is not a member of ‘C’
    std::result_of_t<decltype(&T::f)(Args...)>
    

    इस के आधार पर, मुझे उम्मीद थी कि इलिप्सिस पैरामीटर चाल चलेगा।

  2. दूसरी ओर, भले ही यह काम करता हो, मुझे एक और समस्या होगी: हालांकि A f प्रदान करता है, साथ में अधिभार इलिप्सिस पैरामीटर ओवरलोड रिज़ॉल्यूशन के दौरान चुना जाता है - जहां, निश्चित रूप से, f A द्वारा प्रदान किया जाता है।

(प्रयुक्त संकलक: g++ (उबंटू 8.1.0-5ubuntu1~16.04) 8.1.0; प्रयुक्त मानक: C++14.)

उपरोक्त समस्याओं को हल करने में कोई भी मदद (अधिमानतः दोनों, एक ही समय में) का स्वागत है।

1
laszlzso 27 अक्टूबर 2018, 16:19

1 उत्तर

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

मैं निम्नलिखित X संरचना का प्रस्ताव करता हूं

template <typename T>
struct X
 {
  static void g (...)
   { std::cout << "Operation not supported!" << std::endl; }

  template <typename ... As, typename U = T>
  static auto g(int, As && ... as)
     -> decltype( U::f(std::forward<As>(as)...) )
   { return T::f(std::forward<As>(as)...); }

  template <typename ... As>
  static auto f (As && ... as)
   { return g(0, std::forward<As>(as)...); }
 };

बिंदु हैं

(1) एक अतिरिक्त अप्रयुक्त पैरामीटर के साथ g() फ़ंक्शन से गुजरना (int विविध संस्करण में, "समर्थित संस्करण" में ... द्वारा adsorbed), विविध संस्करण का चयन करने की अनुमति देता है (0 के साथ कॉल किया जाता है जो कि एक int है), जब sizeof...(As) == 0 और दोनों g() फ़ंक्शन उपलब्ध हों। ऐसा इसलिए है क्योंकि int int के लिए ... के रूप में एक बेहतर मिलान (सटीक मिलान में) है। लेकिन जब विविध संस्करण उपलब्ध नहीं है (बिंदु (2) देखें), "गैर समर्थित" संस्करण अभी भी उपलब्ध है (केवल एक उपलब्ध है) और चयनित

(२) आपको SFINAE को वैरिएडिक संस्करण को इस तथ्य के अनुसार सक्षम/अक्षम करना होगा कि f() स्थिर विधि T में उपलब्ध है (या नहीं)। दुर्भाग्य से T वर्ग का एक टेम्पलेट तर्क है, g() स्थिर विधि का नहीं, इसलिए आप इसे SFINAE के लिए उपयोग कर सकते हैं। चाल SFINAE एक अतिरिक्त टेम्पलेट पैरामीटर, U पर संचालित है, जो कि T के लिए डिफ़ॉल्ट है

// ------------------------VVVVVVVVVVVVVV  additional U (defaulted to T) template type
template <typename ... As, typename U = T>
static auto g(int, As && ... as)
   -> decltype( U::f(std::forward<As>(as)...) )
// -------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
// SFINAE enable this g() if (and only if) the call
//   U::f(std::forward<As>(as)...) is valid    

निम्नलिखित एक सरलीकृत कार्य उदाहरण है:

#include <iostream>
#include <type_traits>

struct A
 { static void f() { std::cout << "A::f()" << std::endl; } };

struct B
 {
  static size_t f(std::string const& s_)
   { std::cout << "B::f()" << std::endl; return s_.size(); }
 };

struct C
 { };


template <typename T>
struct X
 {
  static void g (...)
   { std::cout << "Operation not supported!" << std::endl; }

  template <typename ... As, typename U = T>
  static auto g(int, As && ... as)
     -> decltype( U::f(std::forward<As>(as)...) )
   { return T::f(std::forward<As>(as)...); }

  template <typename ... As>
  static auto f (As && ... as)
   { return g(0, std::forward<As>(as)...); }
 };

int main ()
 {
   X<A>::f();  // now call variadic version
   auto const x = X<B>::f("Hello");  // Works just fine as before
   std::cout << x << std::endl;
   X<C>::f();  // now compile
 }
3
max66 27 अक्टूबर 2018, 17:08