[C++] attribute
Updated:
개요
- 타입, 객체, 코드 등에 대한 구현/정의 속성을 설명
- 문법
- C++11
[[ attribute-list ]]
- C++17
[[ using attribute-namespace : attribute-list ]]
- C++11
- 표준 속성
- [[noreturn]]
- C++11
- 함수가 return 하지 않음을 지정
- 함수가 반환되는 경우 동작이 정의되지 않음
- 함수 선언에서 함수 이름에만 적용 가능
- throw 사용하여 함수를 빠져나가야 함
- [[carries_dependency]]
- C++11
- indicates that dependency chain in release-consume std::memory_order propagates in and out of the function
- [[deprecated]] / [[deprecated(“reason”)]]
- C++14
- 사용은 허용되지만 권장되지 않음
- 사용 시 컴파일 경고 발생
- class/struct/union
class [[deprecated]] C;
- typedef/using
[[deprecated]] typedef C* PC;
using PC [[deprecated]] = C*;
- variable
[[deprecated]] int i;
- non-static 데이터 멤버
class T { [[deprecated]] int i; };
- 함수
[[deprecated]] void f();
- namespace
namespace [[deprecated]] NS { int i; }
- enum
enum [[deprecated]] E {};
enum { A [[deprecated]], B [[deprecated]] = 42 };
- C++17
- 템플릿
template <> class [[deprecated]] C<int> {};
- [[fallthrough]]
- C++17
- switch문에서 특정 라벨에 break가 없는게 의도적임을 지정
- 컴파일 경고가 발생하지 않음
- [[nodiscard]] / [[nodiscard(“reason”)]]
- [[nodiscard]]
- C++17
- [[nodiscard(“reason”)]]
- C++20
- 함수의 반환 값을 사용하지 않으면 컴파일 경고 발생
- 해당 속성으로 선언된 함수
- 해당 속성으로 선언된 enum, class 등을 반환하는 함수
- [[nodiscard]]
- [[maybe_unused]]
- C++17
- 사용하지 않는 변수 등에 대한 경고를 억제
- [[likely]] / [[unlikely]]
- C++20
- 컴파일러가 적절한 최적화를 하도록 분기문에 실행 빈도를 지정
- [[no_unique_address]]
- C++20
- non-static 데이터 멤버가 다른 non-static 데이터 멤버와 구별되는 주소를 가질 필요가 없음을 지정
- [[assume]]
- C++23
- 표현식이 항상 true로 평가되도록 지정
- [[noreturn]]
예제
- [[noreturn]]
- 코드
#include <iostream> using namespace std; [[noreturn]] void func1() { throw "throw"; }; void func2 [[noreturn]] () { throw "throw"; }; int main() { try { func1(); } catch (...) { cout << "~~~ func1()" << endl; } try { func2(); } catch (...) { cout << "~~~ func2()" << endl; } return 0; }
- 실행 결과
~~~ func1() ~~~ func2()
- 코드
- [[deprecated]] / [[deprecated(“reason”)]]
- 코드
#include <iostream> #include <string> using namespace std; class [[deprecated]] Test1 { public: void Print() { cout << "Test1::Print()" << endl; } }; class Test2 { public: [[deprecated]] int i; [[deprecated]] void Print() { cout << "Test2::Print()" << endl; } }; template <typename T> class Test3 {}; template <> class [[deprecated]] Test3<int> {}; [[deprecated]] int I = 0; int main() { cout << I << endl; Test1().Print(); Test2().i; Test2().Print(); [[deprecated]] int i = 0; cout << i << endl; Test3<string>(); Test3<int>(); return 0; }
- 실행 결과
main.cpp: In function ‘int main()’: main.cpp:23:17: warning: ‘I’ is deprecated [-Wdeprecated-declarations] 23 | cout << I << endl; | ^ main.cpp:20:20: note: declared here 20 | [[deprecated]] int I = 0; | ^ main.cpp:25:15: warning: ‘Test1’ is deprecated [-Wdeprecated-declarations] 25 | Test1().Print(); | ^ main.cpp:6:22: note: declared here 6 | class [[deprecated]] Test1 { | ^~~~~ main.cpp:27:17: warning: ‘Test2::i’ is deprecated [-Wdeprecated-declarations] 27 | Test2().i; | ^ main.cpp:13:36: note: declared here 13 | [[deprecated]] int i; | ^ main.cpp:27:17: warning: ‘Test2::i’ is deprecated [-Wdeprecated-declarations] 27 | Test2().i; | ^ main.cpp:13:36: note: declared here 13 | [[deprecated]] int i; | ^ main.cpp:27:17: warning: ‘Test2::i’ is deprecated [-Wdeprecated-declarations] 27 | Test2().i; | ^ main.cpp:13:36: note: declared here 13 | [[deprecated]] int i; | ^ main.cpp:28:22: warning: ‘void Test2::Print()’ is deprecated [-Wdeprecated-declarations] 28 | Test2().Print(); | ~~~~~~~~~~~~~^~ main.cpp:14:37: note: declared here 14 | [[deprecated]] void Print() { cout << "Test2::Print()" << endl; } | ^~~~~ main.cpp:31:17: warning: ‘i’ is deprecated [-Wdeprecated-declarations] 31 | cout << i << endl; | ^ main.cpp:30:28: note: declared here 30 | [[deprecated]] int i = 0; | ^ main.cpp:34:20: warning: ‘Test3’ is deprecated [-Wdeprecated-declarations] 34 | Test3<int>(); | ^ main.cpp:18:34: note: declared here 18 | template <> class [[deprecated]] Test3<int> {}; | ^~~~~~~~~~ 0 Test1::Print() Test2::Print() 0
- 코드
- [[fallthrough]]
- 코드
#include <iostream> using namespace std; int main() { int i = 0; switch (i) { case 0: cout << 0 << endl; [[fallthrough]]; case 1: cout << 1 << endl; break; } return 0; }
- 실행 결과
0 1
- 코드
- [[nodiscard]] / [[nodiscard(“reason”)]]
- 코드
class [[nodiscard]] Test {}; Test func1() { return Test(); } [[nodiscard("reason")]] int func2() { return 1; }; int main() { func1(); func2(); return 0; }
- 실행 결과
main.cpp: In function ‘int main()’: main.cpp:7:14: warning: ignoring returned value of type ‘Test’, declared with attribute ‘nodiscard’ [-Wunused-result] 7 | func1(); | ~~~~~^~ main.cpp:2:6: note: in call to ‘Test func1()’, declared here 2 | Test func1() { return Test(); } | ^~~~~ main.cpp:1:21: note: ‘Test’ declared here 1 | class [[nodiscard]] Test {}; | ^~~~ main.cpp:9:14: warning: ignoring return value of ‘int func2()’, declared with attribute ‘nodiscard’: ‘reason’ [-Wunused-result] 9 | func2(); | ~~~~~^~ main.cpp:4:29: note: declared here 4 | [[nodiscard("reason")]] int func2() { return 1; }; | ^~~~~
- 코드
- [[maybe_unused]]
- 코드
[[maybe_unused]] void func([[maybe_unused]] int x, int y) {} int main() { int i = 0; [[maybe_unused]] double d = 0.0; return 0; }
- 실행 결과
main.cpp: In function ‘int main()’: main.cpp:4:13: warning: unused variable ‘i’ [-Wunused-variable] 4 | int i = 0; | ^
- 코드
- [[likely]] / [[unlikely]]
- 코드
#include <algorithm> #include <chrono> #include <iostream> using namespace std; constexpr long long fact_with_attributes(long long n) noexcept { if (n > 1) [[likely]] { return n * fact_with_attributes(n - 1); } else [[unlikely]] { return 1; } } constexpr long long fact_no_attributes(long long n) noexcept { if (n > 1) { return n * fact_no_attributes(n - 1); } else { return 1; } } int main() { auto run = [](auto func) { const auto start = chrono::high_resolution_clock::now(); for (int i = 0; i < 2000000; i++) { for (int j = 0; j <= 20; j++) { func(j); } } const auto end = chrono::high_resolution_clock::now(); const chrono::duration<double> result = end - start; cout << result.count() << endl; }; run(fact_with_attributes); run(fact_no_attributes); return 0; }
- 실행 결과
1.68545 1.7237
- 코드
- [[no_unique_address]]
- 코드
#include <iostream> using namespace std; class Test {}; class Test1 { private: int i; Test t; public: void Print() { cout << &this->i << endl; cout << &this->t << endl; } }; class Test2 { private: int i; [[no_unique_address]] Test t; public: void Print() { cout << &this->i << endl; cout << &this->t << endl; } }; int main() { cout << sizeof(int) << endl; cout << sizeof(Test) << endl; cout << sizeof(Test1) << endl; cout << sizeof(Test2) << endl; cout << "------" << endl; Test1().Print(); cout << "------" << endl; Test2().Print(); return 0; }
- 실행 결과
4 1 8 4 ------ 0x7ffd4e7a40b4 0x7ffd4e7a40b8 ------ 0x7ffd4e7a40bc 0x7ffd4e7a40bc
- 코드