الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

اين الخطأ في هذا الكود "حول القوالب template "

مغلقمُجاب
بدأه Install في 21 فبراير 2014 · 4 رد · 629 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

الكود التالي حول القوالب والتحميل الزائد للدوال 

#include <iostream>
using namespace std;
template <class N,class h>
N hi(N q,N x)
{
    return q+x;
}
h hi(N a,N b)
{
    h xxi = (a==b);
    return xxi;
}
int multiple(int,int);
double multiple(double,double);
int main()
{
  int bx = hi(6,6);
  cout << bx << '\n';
  char bh = hi('1','0');
  cout << bh << '\n';
  bool xx = hi(0,9);
  cout << "0 And 9 Is Equal = " << xx << '\n';
  cout << "9 * 9 is " << multiple(9,9) << '\n';
  cout << "9.9 * 9.9 is " << multiple(9.9,9.9) << '\n';
  return 0;
}
int multiple(int a,int b)
{
    return (a*b);
}
double multiple(double a,double b)
{
    return (a*b);
}

الخطأ 

X:\c++\Pc+\c++\tst\t\main.cpp|17|error: no matching function for call to 'hi(int, int)'|

 

السلام عليكم ورحمة الله

{ وَيَوْمَ تَقُومُ السَّاعَةُ يُقْسِمُ الْمُجْرِمُونَ مَا لَبِثُوا غَيْرَ سَاعَةٍ ۚ كَذَٰلِكَ كَانُوا يُؤْفَكُونَ () وَقَالَ الَّذِينَ أُوتُوا الْعِلْمَ وَالْإِيمَانَ لَقَدْ لَبِثْتُمْ فِي كِتَابِ اللَّهِ إِلَىٰ يَوْمِ الْبَعْثِ ۖ فَهَٰذَا يَوْمُ الْبَعْثِ وَلَٰكِنَّكُمْ كُنْتُمْ لَا تَعْلَمُونَ } الروم 55-56

#2 أفضل إجابة

أول خطأ فى تعريف الدالة hi:

template <class N,class h>
N hi(N q,N x)
{
    return q+x;
}
h hi(N a,N b)
{
    h xxi = (a==b);
    return xxi;
}

كى تقوم بتعريف دالة حره بإستخدام الـ template تحتاج لأن تعرف عناصر الـ template و بالتالي التعريف الثاني لـ hi لابد ان يأخذ الشكل التالي:

template <class N,class h>
h hi(N a,N b)
{
    h xxi = (a==b);
    return xxi;
}

أيضا فى التعريف الأول يوجد الإسم h و لم يتم إستخدامه و سيتسبب فى إظهار رسالة تحذير من المترجم.

 

الخطأ الثاني هو خطأ منطقي  و حتى تفهمه أنظر الكود التالي:

class call
{
public:

	static int test(int a, int b)
	{
		return a + b;
	}
	
	static bool test(int a, int b)
	{
		return a == b;
	}
};

int main()
{
	call::test(10, 11); // which one will be called
}

فى المثال السابق يوجد دالتين بالإسم test داخل الفئه call و تم إستدعاء أحدهم من داخل الدالة main بدون الحصول على القيمه المعاده و هنا ستحدث المشكله فالمترجم لا يعلم اى النسختين انت تريد و لهذا سيظهر لك رسالة خطأ تشبه:

// ambiguous call to overloaded function 'call::test'

السبب فى الخطأ ان بصمة الدالة لا تحتوى على القيمه المعاده و بالتالي كلا الدالتين من وجهة نظر المترجم لهما نفس التعريف و هو كالتالي:

call::test(int,int)

نأتى الأن لكود الـ template الخاص بك. كلا الدالتين hi لهما نفس البصمه و هى:

template<class N, class h> hi(N,N)

عندما قمت بإستدعاء hi كالتالي:

hi(6, 6)

أولا انت لم تقوم بتمرير اسماء الانواع و بهذا سيقوم المترجم بالحصول عليهم من القيم الممره و حيث ان القيم الممرره لها النوع int لذا المترجم سيفترض ان النسخه التى تريد استدعائها لها التعريف:

template<class N> hi(N,N)

و عندما يبحث عنه فإنه لا يجده و لهذا سيقوم بإصدار الرسالة التى تفي انه لا يستطيع إيجاد النسخه التى تريد إستدعائها من الدالة hi.

 

إذا قمت بحذف المعامل h من الدالة hi (التى ترجع N) فالإستدعاء الاول و الثاني لها من داخل main سينجح و سيظهر لك سلوك غريب داخل الإستدعاء الثالث و الذى يعيد bool و السبب هو انك لم تقم بتمرير الأنواع التى تريدها للدالة hi و بالتالي الإستدعاء الثالث سيتم للنسخه الأولى من الدالة hi و ليس الثانية و القيمه المعاده سيتم تحويلها تلقائيا للنوع bool و سيظهر لك المترجم تحذير بأنه سيتم تحويل القيمه من int إلى bool.

 

لحل هذه المشكله إما أن تقوم بتغيير إسم الدالة أو ان تقوم بتمرير النوعين int و bool للدالة hi.

 

قواعد الـ overloading الخاصه بالدوال بدون الـ templates هم نفسهم بها، و تحتاج لأن تفهمهم جيدا بدون الـ templates حتى تستطيع إكتشاف الأخطاء لأن مشاكل الإستدعاء التى قد تنتج عن الـ template مزعجه و تدير الرأس.

 

 

و الله ولي التوفيق

2

مدونتي: C++ Tips and Tricks

#3

جزاك الله خير اخي العزيز على الرد السريع فعلاً 

اقتباس

 

 

كى تقوم بتعريف دالة حره بإستخدام الـ template تحتاج لأن تعرف عناصر الـ template و بالتالي التعريف الثاني لـ hi لابد ان يأخذ الشكل التالي:

لم افهم اين التعديل هل تقصد ان التعريف الخاص بال template للدالة الثانية يجب ان ينسخ فوقها ايضاً اي انسخ التعريف الاول والوحيد الموجود في الأعلى والصقه فوق الدالة الثانية ؟

 

اقتباس

 

 

أيضا فى التعريف الأول يوجد الإسم h و لم يتم إستخدامه و سيتسبب فى إظهار رسالة تحذير من المترجم.

 

فعلا كلامك صحيح ولكن كنت اريد ان اجعل هذا ال template للدالتين معاً هل هناك خطأ في ذلك ؟؟ اي اريد ان يكون ال template هذا موحد للدالتين واردت ان اعبر عن النوع  N مرة int ومرة char والنوع h اريده ان يكون bool

 

 

 

اقتباس

 

 

فى المثال السابق يوجد دالتين بالإسم test داخل الفئه call و تم إستدعاء أحدهم من داخل الدالة main بدون الحصول على القيمه المعاده و هنا ستحدث المشكله فالمترجم لا يعلم اى النسختين انت تريد و لهذا سيظهر لك رسالة خطأ تشبه:

 

ولكن قيل في الموقع الرسمي لل c++ غير هذا الكلام 

 

اقتباس

 

 

Therefore, result will be a variable of the same type as the parameters a and b, and as the type returned by the function.
In this specific case where the generic type T is used as a parameter for sum, the compiler is even able to deduce the data type automatically without having to explicitly specify it within angle brackets. Therefore, instead of explicitly specifying the template arguments with:

1
2 k = sum<int> (i,j);
h = sum<double> (f,g);


It is possible to instead simply write:
1
2 k = sum (i,j);
h = sum (f,g);
without the type enclosed in angle brackets. Naturally, for that, the type shall be unambiguous. If sum is called with arguments of different types, the compiler may not be able to deduce the type of T automatically.
 
 

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

فسوف يكتشف ذلك ال compiler تلقائياً لانها لاترجع قيمة وانت لم تعرف متغير يحمل القيمة -التي تتوقع انت انها سوف ترجع من الدالة - لذلك يكتشف الكومبايلر انك تقصد النسخة التي لا ترجع قيمة 

 

اليس كذلك اخي العزيز ام ان هناك التباس في فهمي للموضوع ؟؟؟

 

بانتظار ردك اخي العزيز بارك الله فيك فلو كان هناك خطأ في فهمي للأمر انا بحاجة لتصحيحه باسرع وقت ممكن

 

ولكم جزيل الشكر

تم تعديل هذه المشاركة بواسطة Install في 21 فبراير 2014 في 19:10

{ وَيَوْمَ تَقُومُ السَّاعَةُ يُقْسِمُ الْمُجْرِمُونَ مَا لَبِثُوا غَيْرَ سَاعَةٍ ۚ كَذَٰلِكَ كَانُوا يُؤْفَكُونَ () وَقَالَ الَّذِينَ أُوتُوا الْعِلْمَ وَالْإِيمَانَ لَقَدْ لَبِثْتُمْ فِي كِتَابِ اللَّهِ إِلَىٰ يَوْمِ الْبَعْثِ ۖ فَهَٰذَا يَوْمُ الْبَعْثِ وَلَٰكِنَّكُمْ كُنْتُمْ لَا تَعْلَمُونَ } الروم 55-56

#4
اقتباس
لم افهم اين التعديل هل تقصد ان التعريف الخاص بال template للدالة الثانية يجب ان ينسخ فوقها ايضاً اي انسخ التعريف الاول والوحيد الموجود في الأعلى والصقه فوق الدالة الثانية ؟

 

 نعم، هذا ما أقصد.

 

اقتباس
فعلا كلامك صحيح ولكن كنت اريد ان اجعل هذا ال template للدالتين معاً هل هناك خطأ في ذلك ؟؟ اي اريد ان يكون ال template هذا موحد للدالتين واردت ان اعبر عن النوع  N مرة int ومرة char والنوع h اريده ان يكون bool

تعريف كل Template function حره - أى ليست داخل class/struct - لابد ان يسبقه تعريف الـ template.

 

جعل دالة واحده لتقوم بعمل الإثنين منطقيا غير صحيح لأن وظيفة كل منهم تختلف عن الأخرى و ايضا القيمه المعاده بكل منهم لها نوع يختلف عن الأخرى.

 

الجمع بين الدوال عموما يكون فى العمليات المتشابهه و التى تعيد نفس النوع مثل ان تكتب دالة واحده للجمع و الطرح و الضرب و القسمه - و هذا تصميم سئ لهذه الحالة - حيث فى كل الأحوال انت ستدخل قيمتين لهما نفس النوع و سترجع قيمه من نفس نوع القيمه المدخله و بهذا يمكنك إستخدام الـ templates لتقليل الكود المكتوب كالتالي:

enum OID { add, sub, mul, div, mod };

template<OID op, class T>
T operation(const T& v1, const T& v2)
{
	switch(op)
	{
	case 0:
		return v1 + v2;
	case 1:
		return v1 - v2;
	case 2:
		return v1 * v2;
	case 3:
		return v1 / v2;
	case 4:
		return v1 % v2;
	default:
		return T();
	}
}

int main()
{
	int r;

	r = operation<add>(3, 1);
	r = operation<sub>(3, 1);
	r = operation<mul>(3, 1);
	r = operation<div>(3, 1);
	r = operation<mod>(3, 1);
}
اقتباس
يجب على الكومبايلر ان يكتشف النوع المناسب تلقائياً ففي المثال الذي طرحته انت اخي العزيز الدالتين ترجع قيمة ففي الحالتين سوف يظهر خطأ لانك لم تعرف متغير ليحمل القيمة المرجعة من الدالتين اما لو كانت احدهما void فسوف يكتشف ذلك ال compiler تلقائياً لانها لاترجع قيمة وانت لم تعرف متغير يحمل القيمة -التي تتوقع انت انها سوف ترجع من الدالة - لذلك يكتشف الكومبايلر انك تقصد النسخة التي لا ترجع قيمة

نوع القيمه المعاده من الدالة ليس جزء منها بصمتها، و لو افترضنا انى استقبلت القيمه المعاده من الدالة كالتالي:

float f = call::test(1, 1);

لاحظ ان النوع int و bool كلاهما يمكن ترقيته ليصبح float و لو افترضنا ان نوع المتغير f كان int فسيظهر من المترجم خطأ ايضا لإن النوع bool يمكن ترقيته للنوع int و إذا كان f نوعها bool فسيظهر المترجم خطأ لأنك تريد تحويل القيمه القيم المعاده تلقائا من int إلى bool و هذا خطأ لأن درجة int أعلى من bool.

 

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

 

عملية المعرفة التقائية للأنواع الخاصه بدوال الـ template عند إستخدامها و بدون تمرير الأنواع تتم بناءا على القيم المدخله لها ففى حالة الدالة sum التى ذكرتها عندما تم تمرير المتغيرين f و g علم المترجم ان نوعهما واحد و هو double و لهذا عرف ان نوع الـ template المدخل هو double و بالمثل المتغيرين i و j2 كلاهما له النوع int و بهذا عرف المترجم ان النوع المدخل int.

 

تخيل ما سيحدث إن قمت بإستخدال متغيرين احداهم من النوع double و الأخر من النوع int، حينها عملية الترجمه ستفشل و السبب ان الدالة تأخذ نوع واحد و انت ادخلت لها اثنين فهل سيتم عمل truncate لقيمة النوع double لتصبح int أم سيتم ترقية فيمة النوع int لتصبح double.

 

الدوال الخاصه بك حاول كتابتهم بدون إستخدام template و تجربة الكود بنوع محدد و بعدها قم بتحويلهم لـ template فإذا عملوا كدوال عادية ففرصة عملهم كدوال template كبيرة.

 

 

 

و الله ولي التوفيق

1

مدونتي: C++ Tips and Tricks

#5
اقتباس

 

 

لقد وصلت إلى الحد الأقصى للنقاط الإيجابية لهذا اليوم

ماشاء الله تبارك الله

فعلا " فاسئلوا اهل الذكر إن كنتم لا تعلمون " صدق الله العظيم

 

بارك الله فيك اخي العزيز النقاش معاك كان مفيد جدا 

فعلا الي بيسئل اهل الخبرة غيير فعلا غيير 

ساعمل بنصائحك ان شاء الله 

جزاكم الله خير

{ وَيَوْمَ تَقُومُ السَّاعَةُ يُقْسِمُ الْمُجْرِمُونَ مَا لَبِثُوا غَيْرَ سَاعَةٍ ۚ كَذَٰلِكَ كَانُوا يُؤْفَكُونَ () وَقَالَ الَّذِينَ أُوتُوا الْعِلْمَ وَالْإِيمَانَ لَقَدْ لَبِثْتُمْ فِي كِتَابِ اللَّهِ إِلَىٰ يَوْمِ الْبَعْثِ ۖ فَهَٰذَا يَوْمُ الْبَعْثِ وَلَٰكِنَّكُمْ كُنْتُمْ لَا تَعْلَمُونَ } الروم 55-56

هذا الموضوع مغلق.

مواضيع مشابهة