constexpr หมายถึงอินไลน์หรือไม่?


105

พิจารณาฟังก์ชันอินไลน์ต่อไปนี้:

// Inline specifier version
#include<iostream>
#include<cstdlib>

inline int f(const int x);

inline int f(const int x)
{
    return 2*x;
}

int main(int argc, char* argv[])
{
    return f(std::atoi(argv[1]));
}

และเวอร์ชันที่เทียบเท่า constexpr:

// Constexpr specifier version
#include<iostream>
#include<cstdlib>

constexpr int f(const int x);

constexpr int f(const int x)
{
    return 2*x;
}

int main(int argc, char* argv[])
{
    return f(std::atoi(argv[1]));
}

คำถามของฉันคือ: ตัวconstexprระบุบ่งบอกถึงตัวinlineระบุหรือไม่ในแง่ที่ว่าถ้าอาร์กิวเมนต์ที่ไม่ใช่ค่าคงที่ถูกส่งผ่านไปยังconstexprฟังก์ชันคอมไพเลอร์จะพยายามinlineใช้ฟังก์ชันราวกับว่ามีการinlineระบุตัวระบุไว้ในการประกาศหรือไม่

มาตรฐาน C ++ 11 รับประกันหรือไม่?


5
'[Will] คอมไพลเลอร์พยายามอินไลน์ฟังก์ชัน' ไม่ใช่สิ่งที่ตัวinlineระบุทำ (หรือบางทีฉันอาจจะเข้าใจวลีของคุณผิด)
Luc Danton

5
ตัวinlineระบุไม่มีส่วนเกี่ยวข้องกับการซับใน
K-ballo

2
คำถามเกี่ยวกับสมมติฐานที่ไม่ถูกต้องซึ่งinlineเกี่ยวข้องโดยตรงกับการฝังใน จึงไม่มีการconstexprระบุไม่ได้หมายความinlineระบุในความรู้สึกว่าเป็นที่ความรู้สึกไม่อยู่
Christian Rau

คำตอบ:


139

ใช่ ([dcl.constexpr], §7.1.5 / 2 ในมาตรฐาน C ++ 11): "ฟังก์ชัน constexpr และตัวสร้าง constexpr เป็นแบบอินไลน์โดยปริยาย (7.1.2)"

อย่างไรก็ตามโปรดทราบว่าตัวinlineระบุมีผลน้อยมาก (ถ้ามี) ต่อคอมไพเลอร์มีแนวโน้มที่จะขยายฟังก์ชันแบบอินไลน์หรือไม่ อย่างไรก็ตามมันมีผลต่อกฎนิยามข้อเดียวและจากมุมมองดังกล่าวคอมไพเลอร์จำเป็นต้องปฏิบัติตามกฎเดียวกันสำหรับconstexprฟังก์ชันที่เป็นinlineฟังก์ชัน

ฉันควรเพิ่มว่าโดยไม่คำนึงถึงconstexprนัยยะinlineกฎสำหรับconstexprฟังก์ชันใน C ++ 11 กำหนดให้ง่ายพอที่พวกเขามักจะเป็นผู้สมัครที่ดีสำหรับการขยายแบบอินไลน์ (ข้อยกเว้นหลักคือสิ่งที่เรียกซ้ำ) อย่างไรก็ตามตั้งแต่นั้นมากฎก็ค่อยๆคลายลงเรื่อย ๆ ดังนั้นจึงconstexprสามารถนำไปใช้กับฟังก์ชันที่ใหญ่กว่าและซับซ้อนมากขึ้นได้


เนื่องจากแนวคิดคือนิพจน์คงที่ได้รับการประเมินในเวลาคอมไพล์ฉันคิดว่าการใช้constexprฟังก์ชันส่วนใหญ่จะไม่ทำให้เกิดการสร้างโค้ดเลย ...
Kerrek SB

11
constexprฟังก์ชัน@KerrekSB อาจได้รับการประเมินในเวลาคอมไพล์ อย่างไรก็ตามมาตรฐาน C ++ 14 นั้นเกลื่อนไปด้วยมาตรฐานซึ่งมีโอกาสมากที่จะถูกเรียกเมื่อรันไทม์ ตัวอย่าง:std::array<T,N>::at
Eponymous

@ ไม่ระบุชื่อใช่ แต่มีเพียงรูปแบบที่ลดลงมากที่สุดเท่านั้นที่จะยังคงเป็น opcodes เช่น: การตรวจสอบที่ถูกผูกไว้จะได้รับการประเมิน ณ เวลาสร้างเนื่องจากเส้นทางรหัสเป็น const แต่ค่าที่ส่งกลับจะเป็น * (data + offset)
v.oddou

16

constexprไม่ได้หมายความถึงinlineตัวแปรที่ไม่คงที่ (ตัวแปรอินไลน์ C ++ 17)

แม้ว่าconstexprจะบ่งบอกถึงinlineฟังก์ชัน แต่ก็ไม่มีผลสำหรับตัวแปรที่ไม่คงที่โดยพิจารณาจากตัวแปรอินไลน์ C ++ 17

ตัวอย่างเช่นหากคุณใช้ตัวอย่างขั้นต่ำที่ฉันโพสต์ไว้ที่: ตัวแปรอินไลน์ทำงานอย่างไร และลบinlineออกจากconstexprนั้นตัวแปรจะได้รับหลายแอดเดรสซึ่งเป็นสิ่งสำคัญที่ตัวแปรอินไลน์หลีกเลี่ยง

constexpr อย่างไรก็ตามตัวแปรคงที่โดยปริยาย

ตัวอย่างน้อยที่สุดที่constexprแสดงถึงinlineฟังก์ชัน

ตามที่กล่าวไว้ที่: https://stackoverflow.com/a/14391320/895245ผลกระทบหลักinlineคือไม่อยู่ในบรรทัด แต่อนุญาตให้มีคำจำกัดความหลายฟังก์ชันคำพูดมาตรฐานที่: ไฟล์ส่วนหัว C ++ จะรวมการนำไปใช้งานได้อย่างไร?

เราสามารถสังเกตได้โดยการเล่นตามตัวอย่างต่อไปนี้:

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    assert(shared_func() == notmain_func());
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

inline int shared_func() { return 42; }
int notmain_func();

#endif

notmain.cpp

#include "notmain.hpp"

int notmain_func() {
    return shared_func();
}

รวบรวมและเรียกใช้:

g++ -c -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'notmain.o' 'notmain.cpp' 
g++ -c -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'main.o' 'main.cpp' 
g++ -ggdb3  -O0 -Wall -Wextra -std=c++11 -pedantic-errors  -o 'main.out' notmain.o main.o
./main.out

หากเราลบinlineจากshared_funcการเชื่อมโยงจะล้มเหลวด้วย:

multiple definition of `shared_func()'

เนื่องจากส่วนหัวรวมอยู่ใน.cppไฟล์หลายไฟล์

แต่ถ้าเราแทนที่inlineด้วยconstexprมันก็จะใช้งานได้อีกครั้งเพราะconstexprก็มีนัยinlineเช่นกัน

GCC ดำเนินการโดยการทำเครื่องหมายสัญลักษณ์ว่าอ่อนแอในไฟล์อ็อบเจ็กต์ ELF: ไฟล์ส่วนหัว C ++ จะรวมการนำไปใช้งานได้อย่างไร?

ทดสอบใน GCC 8.3.0


3
BTW ตัวแปรสมาชิกคลาสคงที่ประกาศconstexprยังคงเป็นแบบอินไลน์ cppreference.com : ตัวแปรสมาชิกแบบคงที่ (แต่ไม่ใช่ตัวแปรขอบเขตเนมสเปซ) ที่ประกาศconstexprโดยปริยายเป็นตัวแปรอินไลน์
anton_rh

@anton_rh ขอบคุณฉันไม่เห็นกฎนั้นอัปเดตคำตอบ
Ciro Santilli 郝海东冠状病六四事件法轮功

ไม่ใช่สิ่งที่open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0386r0.pdfพูด มันบอกว่า constexpr หมายถึงอินไลน์สำหรับตัวแปร โดยไม่มีการกล่าวถึงความแตกต่างระหว่างขอบเขตเนมสเปซของขอบเขตคลาส
v.oddou
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.