ไม่ สิ่งนี้เรียกว่าโอเวอร์โหลด และไม่ใช่ฟีเจอร์ที่ C มี คุณควรสร้างฟังก์ชัน ที่แตกต่าง เพื่อจัดการกับสิ่งนี้
คุณ สามารถ ทำมันได้ด้วยตัวช่วยสร้าง C ทุกประเภท (คุณสามารถ อะไรก็ได้ ด้วยตัวช่วยสร้าง C ที่เพียงพอ) แต่โค้ดที่ได้ออกมาอาจจะดูน่าเกลียดจนไม่สามารถบำรุงรักษาได้ : -)
ตัวอย่างเช่น C11 แนะนำการเลือกทั่วไปด้วยนิพจน์หลัก _Generic
และสิ่งนี้ทำให้คุณสามารถเรียกใช้ฟังก์ชันต่างๆ ตามประเภทอาร์กิวเมนต์อินพุต จริงๆ แล้วมันไม่ได้ทำอะไรมากกว่านั้นอีกสักหน่อย แต่นั่นคือสิ่งที่คุณสนใจตามคำถามของคุณ
ตัวอย่างเช่น สมมติว่าคุณกำหนดฟังก์ชันสองฟังก์ชันดังนี้:
int diffi (int a, int b) { return a - b; }
double diffd (double a, double b) { return a - b; }
โดยปกติแล้วคุณจะต้องตัดสินใจว่าจะโทรสายใดโดยพิจารณาจากประเภทอินพุตของคุณ คุณสมบัติการเลือกทั่วไปของ C11 ช่วยให้คุณทำสิ่งนี้ได้:
#define diff(a,b) \
_Generic((a), \
double: diffd, \
int: diffi, \
default: diffX \
)(a,b)
และสิ่งนี้ทำโดยพื้นฐานในการค้นหามาโคร diff(x,y)
ในซอร์สโค้ด:
- กำหนดประเภทของนิพจน์
(a)
โดยไม่ต้องประเมิน
- ฉีดโทเค็นที่ตรงกับประเภทนั้นลงในสตรีมต้นทาง (หรือค่าเริ่มต้นหากไม่พบรายการที่ตรงกัน)
- แทรกข้อความ
(a,b)
ลงในสตรีมต้นทางในตอนท้าย
ดังนั้น หากไฟล์ต้นฉบับของคุณมีบรรทัด:
x = diff (1, 2);
y = diff (1.0, 2);
สิ่งนี้จะถูกแปลเป็น:
x = diffi (1 , 2);
y = diffd (1.0, 2);
ให้คุณโอเวอร์โหลดได้อย่างมีประสิทธิภาพ
ตอนนี้เป็นกรณีที่ง่ายพอสมควรเนื่องจากอาศัยเฉพาะอาร์กิวเมนต์ประเภทแรกเท่านั้น - คุณจะเห็นช่องโหว่หากคุณพยายามทำ:
z = diff (1, 2.0);
โดยที่ประเภทของอาร์กิวเมนต์ แรก คือ int
ดังนั้นคุณจะได้รับ:
z = diffi (1, 2.0);
ซึ่งจะไม่ใช่สิ่งที่คุณต้องการทำจริงๆ นี่คือที่มาของความซับซ้อน เนื่องจากคุณต้องครอบคลุมความเป็นไปได้ สี่: {int/int, int/double, double/int, double/double}
และจะซับซ้อน มากขึ้น ขึ้นอยู่กับจำนวนอาร์กิวเมนต์และประเภทที่เป็นไปได้สำหรับแต่ละอาร์กิวเมนต์
อย่างไรก็ตาม กรณีทั้งหมดของคุณนั้นสามารถทำได้โดยใช้ค่าเริ่มต้นอย่างรอบคอบและการเลือกทั่วไปที่ซ้อนกัน เช่น:
#define diff(a,b) \
_Generic((a), \
double: diffd, \
default: _Generic((b), \
double: diffd, \
default: diffi \
) \
)(a,b)
และสิ่งนี้สามารถอ่านได้เป็น:
- ถ้าประเภทของ
a
คือ double
ให้ใช้ diffd
;
- มิฉะนั้น หากประเภทของ
b
คือ double
ให้ใช้ diffd
;
- มิฉะนั้นให้ใช้
diffi
- อย่าลืมใส่ข้อโต้แย้งด้วย
โปรแกรมที่สมบูรณ์ต่อไปนี้ (คอมไพล์ด้วย clang 3.0
) จะแสดงคุณลักษณะนี้ในการทำงาน:
#include <stdio.h>
int diffi (int a, int b) {
printf ("diffi %d %d", a, b);
return a - b;
}
double diffd (double a, double b) {
printf ("diffd %f %f", a, b);
return a - b;
}
#define diff(a,b) \
_Generic((a), \
double: diffd, \
default: _Generic((b), \
double: diffd, \
default: diffi \
) \
)(a,b)
int main (void) {
int i; double d;
i = diff (1 , 2 ); printf (" --> %d\n", i);
d = diff (1.0, 2 ); printf (" --> %f\n", d);
d = diff (1 , 2.0); printf (" --> %f\n", d);
d = diff (1.0, 2.0); printf (" --> %f\n", d);
return 0;
}
ผลลัพธ์ของโปรแกรมนั้นคือ:
diffi 1 2 --> -1
diffd 1.000000 2.000000 --> -1.000000
diffd 1.000000 2.000000 --> -1.000000
diffd 1.000000 2.000000 --> -1.000000
แสดงว่ามีการเรียกฟังก์ชันที่ถูกต้องสำหรับความเป็นไปได้ทั้งสี่ประการ
และในความเป็นจริง ตามที่ rici ชี้ให้เห็นในความคิดเห็น คุณสามารถพึ่งพากฎการส่งเสริมของ C โดยที่การเพิ่ม double
และ int
(ตามลำดับใดๆ ก็ตาม) จะให้ double
ในขณะที่การเพิ่มตัวแปร int
สองตัวจะให้ int
:
#define diff(a,b) _Generic((a+b), double:diffd, default:diffi)(a,b)
person
paxdiablo
schedule
21.10.2014