C ประกาศฟังก์ชั่น
ก่อนอื่นมี C. ใน C A a()
คือการประกาศฟังก์ชัน ตัวอย่างเช่นputchar
มีการประกาศดังต่อไปนี้ โดยปกติแล้วการประกาศดังกล่าวจะถูกเก็บไว้ในไฟล์ส่วนหัว แต่ไม่มีอะไรหยุดคุณจากการเขียนด้วยตนเองหากคุณรู้ว่าการประกาศฟังก์ชั่นมีลักษณะอย่างไร ชื่ออาร์กิวเมนต์เป็นทางเลือกในการประกาศดังนั้นฉันจึงละเว้นในตัวอย่างนี้
int putchar(int);
สิ่งนี้อนุญาตให้คุณเขียนโค้ดแบบนี้
int puts(const char *);
int main() {
puts("Hello, world!");
}
C ยังช่วยให้คุณสามารถกำหนดฟังก์ชั่นที่รับฟังก์ชั่นเป็นอาร์กิวเมนต์โดยมีไวยากรณ์ที่อ่านง่ายซึ่งดูเหมือนว่าจะเป็นการเรียกใช้ฟังก์ชัน (เช่นกันมันสามารถอ่านได้
#include <stdio.h>
int eighty_four() {
return 84;
}
int output_result(int callback()) {
printf("Returned: %d\n", callback());
return 0;
}
int main() {
return output_result(eighty_four);
}
ดังที่ฉันได้กล่าวไว้ C อนุญาตให้ละเว้นชื่ออาร์กิวเมนต์ในไฟล์ส่วนหัวดังนั้นoutput_result
จะมีลักษณะเช่นนี้ในไฟล์ส่วนหัว
int output_result(int());
หนึ่งอาร์กิวเมนต์ในตัวสร้าง
คุณจำไม่ได้เหรอ? ผมขอเตือนคุณ
A a(B());
ใช่มันเป็นฟังก์ชั่นการประกาศเดียวกัน A
เป็นint
, a
เป็นoutput_result
และเป็นB
int
คุณสามารถสังเกตเห็นความขัดแย้งของ C ได้อย่างง่ายดายด้วยคุณสมบัติใหม่ของ C ++ เป็นที่แน่นอนก่อสร้างเป็นชื่อชั้นและวงเล็บและไวยากรณ์ประกาศสลับกับแทน()
=
จากการออกแบบ C ++ พยายามที่จะเข้ากันได้กับรหัส C และดังนั้นจึงต้องจัดการกับกรณีนี้ - แม้ว่าจะไม่มีใครใส่ใจ ดังนั้นคุณสมบัติ C เก่าจึงมีความสำคัญเหนือกว่าคุณสมบัติ C ++ ใหม่ ไวยากรณ์ของการประกาศพยายามที่จะจับคู่ชื่อเป็นฟังก์ชั่นก่อนที่จะย้อนกลับไปที่ไวยากรณ์ใหม่ด้วย()
ถ้ามันล้มเหลว
หากหนึ่งในคุณลักษณะเหล่านั้นไม่มีอยู่หรือมีไวยากรณ์ที่แตกต่างกัน (เช่น{}
ใน C ++ 11) ปัญหานี้จะไม่เกิดขึ้นสำหรับไวยากรณ์ด้วยอาร์กิวเมนต์เดียว
ตอนนี้คุณอาจถามว่าทำไมA a((B()))
งาน ดีขอประกาศของoutput_result
มีวงเล็บไร้ประโยชน์
int output_result((int()));
มันจะไม่ทำงาน ไวยากรณ์ต้องการตัวแปรที่ไม่อยู่ในวงเล็บ
<stdin>:1:19: error: expected declaration specifiers or ‘...’ before ‘(’ token
อย่างไรก็ตาม C ++ คาดว่านิพจน์มาตรฐานที่นี่ ใน C ++ คุณสามารถเขียนรหัสต่อไปนี้
int value = int();
และรหัสต่อไปนี้
int value = ((((int()))));
C ++ คาดว่านิพจน์ภายในวงเล็บจะเป็น ... ทั้ง ... นิพจน์ตรงข้ามกับประเภท C ที่คาดไว้ วงเล็บไม่ได้มีความหมายอะไรเลย อย่างไรก็ตามโดยการใส่วงเล็บที่ไม่มีประโยชน์การประกาศฟังก์ชัน C ไม่ตรงกันและไวยากรณ์ใหม่สามารถจับคู่ได้อย่างถูกต้อง (ซึ่งคาดว่าจะแสดงออกเช่น2 + 2
)
อาร์กิวเมนต์เพิ่มเติมในตัวสร้าง
แน่นอนหนึ่งอาร์กิวเมนต์เป็นสิ่งที่ดี แต่สิ่งที่เกี่ยวกับสอง? ไม่ใช่ว่าผู้สร้างอาจมีข้อโต้แย้งเพียงข้อเดียว หนึ่งในคลาสที่มีอาร์กิวเมนต์สองตัวคือstd::string
std::string hundred_dots(100, '.');
ทั้งหมดนี้เป็นเรื่องที่ดีและดี (โดยทางเทคนิคแล้วมันจะมีการแยกวิเคราะห์ส่วนใหญ่ถ้ามันจะเขียนเป็นstd::string wat(int(), char())
แต่ขอซื่อสัตย์ - ผู้ที่จะเขียนว่า แต่ขอสมมติว่ารหัสนี้มีปัญหาน่ารำคาญคุณจะคิดว่าคุณต้องใส่ ทุกอย่างในวงเล็บ
std::string hundred_dots((100, '.'));
ไม่มาก
<stdin>:2:36: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
In file included from /usr/include/c++/4.8/string:53:0,
from <stdin>:1:
/usr/include/c++/4.8/bits/basic_string.tcc:212:5: error: initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
basic_string<_CharT, _Traits, _Alloc>::
^
ฉันไม่แน่ใจว่าทำไมกรัม ++ พยายามที่จะแปลงไปchar
const char *
ไม่ว่าจะด้วยวิธีใดตัวสร้างจะถูกเรียกด้วยค่าชนิดchar
เดียว ไม่มีโอเวอร์โหลดที่มีอาร์กิวเมนต์ชนิดchar
เดียวดังนั้นคอมไพเลอร์จึงสับสน คุณอาจถามว่า - ทำไมอาร์กิวเมนต์เป็นประเภทถ่าน?
(100, '.')
ใช่,
นี่คือโอเปอเรเตอร์คอมม่า ตัวดำเนินการเครื่องหมายจุลภาคใช้เวลาสองข้อโต้แย้งและให้อาร์กิวเมนต์ด้านขวา มันไม่มีประโยชน์จริง ๆ แต่เป็นสิ่งที่เป็นที่รู้จักสำหรับคำอธิบายของฉัน
แต่เพื่อแก้ปัญหาการแจงส่วนใหญ่ต้องใช้รหัสต่อไปนี้แทน
std::string hundred_dots((100), ('.'));
อาร์กิวเมนต์อยู่ในวงเล็บไม่ใช่นิพจน์ทั้งหมด ในความเป็นจริงแล้วนิพจน์เพียงข้อเดียวจำเป็นต้องอยู่ในวงเล็บเนื่องจากมันเพียงพอที่จะแยกจากไวยากรณ์ C เล็กน้อยเพื่อใช้คุณลักษณะ C ++ สิ่งต่าง ๆ นำเราไปสู่จุดที่ไม่มีข้อโต้แย้ง
ไม่มีข้อโต้แย้งในตัวสร้าง
คุณอาจสังเกตเห็นeighty_four
ฟังก์ชั่นในคำอธิบายของฉัน
int eighty_four();
ใช่สิ่งนี้ได้รับผลกระทบจากการแยกวิเคราะห์ที่รบกวนที่สุด มันเป็นคำจำกัดความที่ถูกต้องและเป็นไปได้ว่าคุณเคยเห็นถ้าคุณสร้างไฟล์ส่วนหัว (และคุณควร) การเพิ่มวงเล็บไม่สามารถแก้ไขได้
int eighty_four(());
เหตุผลที่เป็นเช่นนั้น? ดี()
ไม่ได้เป็นการแสดงออก ใน C ++ คุณต้องใส่นิพจน์ระหว่างวงเล็บ คุณไม่สามารถเขียนauto value = ()
ด้วยภาษา C ++ ได้เพราะ()
ไม่ได้หมายความว่าอะไร (และแม้ว่าจะเป็นเช่นเดียวกับ tuple ที่ว่างเปล่า (ดู Python) ก็จะเป็นหนึ่งอาร์กิวเมนต์ไม่ใช่ศูนย์) ในทางปฏิบัติหมายความว่าคุณไม่สามารถใช้ไวยากรณ์ชวเลขได้โดยไม่ต้องใช้ไวยากรณ์ของ C ++ 11 {}
เนื่องจากไม่มีนิพจน์ที่จะใส่ในวงเล็บและไวยากรณ์ C สำหรับการประกาศฟังก์ชันจะใช้เสมอ
(B())
เป็นเพียงการแสดงออก C ++ ไม่มีอะไรเพิ่มเติม มันไม่มีข้อยกเว้นใด ๆ ความแตกต่างเพียงอย่างเดียวที่ทำให้เป็นคือไม่มีวิธีที่จะแยกวิเคราะห์เป็นประเภทและดังนั้นจึงไม่