سؤال

أود أن أكون قادرًا على استخدام خصم القالب لتحقيق ما يلي:

GCPtr<A> ptr1 = GC::Allocate();
GCPtr<B> ptr2 = GC::Allocate();

بدلاً من (ما لدي حاليًا):

GCPtr<A> ptr1 = GC::Allocate<A>();
GCPtr<B> ptr2 = GC::Allocate<B>();

تبدو وظيفة تخصيص بلدي الحالية مثل هذا:

class GC
{
public:
    template <typename T>
    static GCPtr<T> Allocate();
};

هل سيكون هذا ممكنًا لإيقاف الإضافة <A> و <B>?

هل كانت مفيدة؟

المحلول

لا يمكن القيام بذلك. لا يشارك نوع الإرجاع في خصم النوع ، بل إنه نتيجة لمطابقة توقيع القالب المناسب بالفعل. يمكنك ، مع ذلك ، إخفاءها من معظم الاستخدامات على النحو التالي:

// helper
template <typename T>
void Allocate( GCPtr<T>& p ) {
   p = GC::Allocate<T>();
}

int main()
{
   GCPtr<A> p = 0;
   Allocate(p);
}

سواء كان هذا الجملة هو في الواقع أفضل أو أسوأ من الأولي GCPtr<A> p = GC::Allocate<A>() هو سؤال آخر.

سيسمح لك PS C ++ 11 بتخطي أحد إعلانات النوع:

auto p = GC::Allocate<A>();   // p is of type GCPtr<A>

نصائح أخرى

الشيء الوحيد الذي يمكنني التفكير فيه: اجعل تخصيصًا غير مملوك يعيد كائن وكيل غير مملوك له مشغل تحويل تمثل يقوم بالعمل الحقيقي:

template <class T>
struct GCPtr
{

};

class Allocator
{
public:
    template <class T>
    operator GCPtr<T>() { return GCPtr<T>(); }
};

class GC
{
public:
    static Allocator Allocate() { return Allocator(); }//could give a call-back pointer?
};

int main()
{
    GCPtr<int> p = GC::Allocate();
}

هل يمكن أن تسير في الطريق المعاكس.

إذا كنت تستخدم برنامج التحويل البرمجي المحدث (MSVC 2010 والذي يجب أن يكون في غضون يومين ، أو الإصدار الحالي من GCC) ولا تمانع في الاعتماد على ميزات C ++ 0x:

auto ptr1 = GC::Allocate<A>();
auto ptr2 = GC::Allocate<B>();

سوف يوفر لك الإضافية <A> و <B>, ، ليس فقط على الجانب الأيمن. قون

(هذه الإجابة هي نفسها مثل unclebens ، ولكنها أكثر عمومية لأنها مثالية إلى الأمام.

هذا مفيد جدًا في لغات مثل Haskell حيث ، على سبيل المثال ، read سوف تأخذ سلسلة كمدخلات وسوف تحليلها وفقا لنوع الإرجاع المطلوب.

(هنا عينة رمز على ideone.)

أولاً ، ابدأ بالوظيفة foo من نوع العودة نود أن نستنتج:

template<typename Ret>
Ret foo(const char *,int);
template<>
std::string foo<std::string>(const char *s,int) { return s; }
template<>
int         foo<int        >(const char *,int i) { return i; }

عندما يُطلب من سلسلة ، ستعيد السلسلة الموجودة في الوسيطة الأولى. عندما يُطلب من int ، ستعيد الوسيطة الثانية.

يمكننا تحديد وظيفة auto_foo يمكن استخدامها على النحو التالي:

int main() {
        std::string s = auto_foo("hi",5); std::cout << s << std::endl;
        int         i = auto_foo("hi",5); std::cout << i << std::endl;
}

لجعل هذا العمل ، نحتاج إلى كائن من شأنه تخزين وسيطات الوظائف مؤقتًا ، وكذلك تشغيل الوظيفة عندما يُطلب منه ذلك يتحول إلى نوع الإرجاع المطلوب:

#include<tuple>

template<size_t num_args, typename ...T>
class Foo;
template<typename ...T>
class Foo<2,T...> : public std::tuple<T&&...>
{
public: 
        Foo(T&&... args) :
                std::tuple<T&&...>(std::forward<T>(args)...)
        {}
        template< typename Return >
        operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this)); }
};
template<typename ...T>
class Foo<3,T...> : std::tuple<T&&...>
{
public: 
        Foo(T&&... args) :
                std::tuple<T&&...>(std::forward<T>(args)...)
        {}
        template< typename Return >
        operator Return() { return foo<Return>(std::get<0>(*this), std::get<1>(*this), std::get<2>(*this)); }
};

template<typename ...T>
auto
auto_foo(T&&... args)
        // -> Foo<T&&...> // old, incorrect, code
        -> Foo< sizeof...(T), T&&...> // to count the arguments
{
        return              {std::forward<T>(args)...};
}

أيضًا ، يعمل ما ورد أعلاه لوظائف ARG أو ثلاثية ARG ، ليس من الصعب معرفة كيفية تمديد ذلك.

هذا هو الكثير من التعليمات البرمجية للكتابة! لكل وظيفة ستقوم بتطبيقها على ذلك ، يمكنك كتابة ماكرو يقوم بذلك نيابة عنك. شيء من هذا القبيل في الجزء العلوي من ملفك:

REGISTER_FUNCTION_FOR_DEDUCED_RETURN_TYPE(foo); // declares
                        // necessary structure and auto_???

وبعد ذلك يمكنك استخدامه auto_foo في برنامجك.

بنفس الطريقة لا يمكنك التحميل الزائد في نوع الإرجاع ، لا يمكنك إجراء خصم القالب عليه. وللسبب نفسه - إذا كان f () هو قالب/تحميل زائد يرجع شيء ما ، فما النوع الذي يجب استخدامه هنا:

f();

يمكنك محاولة استخدام ماكرو لذلك. بخلاف ذلك ، لا أرى كيف من المفترض أن يعمل ببيان واحد فقط.

#define ALLOC(ptrname,type) GCPtr<type> ptrname = GC::Allocate<type>()

ALLOC(ptr1,A);

نقاط يوهانس صالحة. يتم إصلاح المشكلة >> بسهولة. لكنني أعتقد أن وجود فواصل كجزء من النوع يتطلب امتداد C99 Preprocessor Varargs:

#define ALLOC(ptrname,...) GCPtr< __VA_ARGS__ > ptrname = GC::Allocate< __VA_ARGS__ >()

ALLOC(ptr1,SomeTemplate<int,short>);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top