سؤال

لدي المشكلة التالية باستخدام قالب مثيل [*].

الملف فو.ح

class Foo
{
public:
    template <typename F>
    void func(F f)

private:
    int member_;
};

الملف foo.cc

template <typename F>
Foo::func(F f)
{
     f(member_);
}

الملف caller.cc

Foo::func(boost::bind(&Bar::bar_func, bar_instance, _1));

في حين أن هذا يجمع بخير, رابط يشكو من غير معرفة الرمز:

void Foo::func<boost::_bi::bind_t...>

كيف يمكنني إنشاء مثيل وظيفة Foo::func?لأنه يأخذ وظيفة الحجة ، أنا قليلا الخلط.حاولت إضافة مثيل وظيفة في foo.cc, كما اعتدت على دورية غير دالة أنواع:

instantiate()
{
    template<> void Foo::func<boost::function<void(int)> >(boost::function<void(int)>);
}

ومن الواضح أن هذا لا يعمل.وسأكون ممتنا إذا كان شخص ما يمكن لي نقطة في الاتجاه الصحيح.

وذلك بفضل!

[*] نعم ، لقد قرأت parashift التعليمات لايت.

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

المحلول

الجواب على هذا هو مترجم تعتمد.بعض الإصدارات من الشمس C++ compiler سيكون التعامل مع هذا تلقائيا من خلال بناء ذاكرة التخزين المؤقت من قالب وظيفة التطبيقات التي من شأنها أن تكون مشتركة عبر منفصلة وحدات الترجمة.

إذا كنت تستخدم Visual C++ وغيرها من المترجم لا يمكن أن تفعل هذا ، يمكنك كذلك وضع تعريف الدالة في الرأس.

لا تقلق بشأن تكرار التعاريف إذا كان رأس وشملت متعددة .cc الملفات.مترجم علامات قالب إنشاء الطرق مع سمة خاصة إذا linker يعرف لرمي بعيدا مكررة بدلا من الشكوى.وهذا هو أحد الأسباب لماذا C++ لديه "تعريف واحد القاعدة".

تحرير: التعليقات الواردة أعلاه ينطبق في الحالة العامة حيث القالب الخاص بك يجب أن تكون قادرة على ربط أي نوع المعلمات.إذا كنت تعرف مجموعة مغلقة من أنواع العملاء سوف تستخدم, يمكنك التأكد من أنها متاحة باستخدام إنشاء مثيل صريح في القالب تنفيذ الملف الذي سوف يتسبب برنامج التحويل البرمجي لإنشاء تعريفات الملفات الأخرى لربط ضد.ولكن في الحالة العامة حيث القالب الخاص بك يحتاج إلى العمل مع أنواع ربما المعروفة فقط إلى العميل ، ثم هناك نقطة صغيرة في فصل القالب إلى ملف الرأس و تنفيذ الملف ؛ أي عميل يجب أن تشمل كل أجزاء على أي حال.إذا كنت ترغب في عزل العملاء من مجمع تبعيات إخفاء تلك التبعيات وراء عدم قالب المهام ثم الدعوة إليها من قالب المدونة.

نصائح أخرى

تقسيمه إلى الملفات كما تريد:
لا أن أوصي هذا.فقط تظهر أنه من الممكن.

صوت نزول المطر.ح

#include <iostream>
class Foo
{
public:
    Foo(): member_(15){}


    // Note No definition of this in a header file.
    // It is defined in plop.cpp and a single instantiation forced
    // Without actually using it.
    template <typename F>
    void func(F f);

private:
    int member_;
};


struct Bar
{
     void bar_func(int val) { std::cout << val << "\n"; }
};

struct Tar
{
    void tar_func(int val) { std::cout << "This should not print because of specialisation of func\n";}
};

Plop.cpp

#include "plop.h"
#include <boost/bind.hpp>
#include <iostream>

template <typename F>
void Foo::func(F f)
{
     f(member_);
}

// Gnarly typedef
typedef boost::_bi::bind_t<void, boost::_mfi::mf1<void, Bar, int>, boost::_bi::list2<boost::_bi::value<Bar>, boost::arg<1> (*)()> > myFunc;

// Force the compiler to generate an instantiation of Foo::func()
template void Foo::func<myFunc>(myFunc f);

// Note this is not a specialization as that requires the <> after template.
// See main.cpp for an example of specialization.

main.cpp

#include "plop.h"
#include <boost/bind.hpp>
#include <iostream>

// Gnarly typedef
typedef boost::_bi::bind_t<void, boost::_mfi::mf1<void, Tar, int>, boost::_bi::list2<boost::_bi::value<Tar>, boost::arg<1> (*)()> > myTar;

// Specialization of Foo::func()
template<> void Foo::func<myTar>(myTar f)
{
    std::cout << "Special\n";
}
// Note. This is not instantiated unless it is used.
// But because it is used in main() we get a version.

int main(int argc,char* argv[])
{
    Foo f;
    Bar b;
    Tar t;

    f.func(boost::bind(&Bar::bar_func, b, _1)); // Uses instantiation from plop.cpp
    f.func(boost::bind(&Tar::tar_func, t, _1)); // Uses local specialization
}

هل أنت بما في ذلك foo.cc في caller.cc.مثيل هو شيء يحدث في وقت الترجمة-عندما مترجم يرى الدعوة في المتصل يجعل مثيل إصدارات قوالب بل يحتاج إلى التعريف الكامل المتاحة.

ما أعتقد انهم على حد سواء مشيرا إلى أن قالب تعريفات الدالة (ليس فقط الإعلانات) يجب أن تكون مدرجة في الملف حيث انهم المستخدمة.قالب وظائف لا وجود لها في الواقع إلا إذا/حتى انهم المستخدمة ؛ إذا كنت وضعت لهم في فصل cc الملف ، ثم المترجم لا يعرف عنهم في الآخر cc الملفات إلا إذا كنت صراحة #include أن cc الملف إلى ملف الرأس أو الملف الذي يدعو لهم ، بسبب الطريقة محلل يعمل.

(وهذا هو السبب في قالب تعريفات الدالة عموما تبقى في رأس الملفات ، Earwicker وصفها.)

أوضح ؟

أعتقد Earwicker هو الصحيح.مشكلة صراحة إنشاء قالب وظيفة عضو وظائفها في هذه الحالة هو أن نوع إرجاعها بواسطة دفعة::ربط التنفيذ تعتمد.فمن لا دفعة::وظيفة.دفعة::وظيفة يمكن أن تحتوي على دفعة:ربط لأنه يحتوي على قالب عامل التعيين أن يستنتج نوع من الجهة اليمنى (دفعة::مأزق نتيجة).في هذا الخصوص استخدام وظائفها في caller.cc هذا الأمر خاصة تنفيذ دفعة ، نوع من دفعة::مأزق هو في الواقع نوع المذكورة في رابط خطأ بين < و > (ie. boost::_bi::bind_t...).لكن صراحة إنشاء ظائفها لهذا النوع من المحتمل سيكون لديك قابلية المشاكل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top