속성(Attributes)

속성(Attributes)

컴파일러마다 가진 확장 기능을 표준적인 문법 하나로 통일해 쓰고 싶을 때가 있어요. C++11부터 도입된 **속성(attributes)**이 바로 그 역할을 해요. 속성은 타입, 객체, 코드 등에 대한 구현 정의(implementation-defined) 속성을 도입하는 표준 문법이에요.

출처: cppreference

본문

문법

[[ attribute-list ]] (C++11부터)
[[ using attribute-namespace : attribute-list ]] (C++17부터)

여기서 attribute-list는 0개 이상의 속성들의 쉼표로 구분된 시퀀스예요(팩 확장을 나타내는 줄임표 ...로 끝날 수 있어요).

식별자 (1)
attribute-namespace :: 식별자 (2)
식별자 ( argument-list(optional) ) (3)
attribute-namespace :: 식별자 ( argument-list(optional) ) (4)

여기서 attribute-namespace는 식별자이고, argument-list는 괄호·대괄호·중괄호가 균형 잡힌 토큰 시퀀스(balanced-token-seq)예요.

속성 목록의 시작에 using namespace:가 나오면, 속성 목록의 다른 속성들은 이름공간을 지정할 수 없어요. using에 지정된 이름공간이 그 모두에 적용되거든요. (C++17부터)

[[using CC: opt(1), debug]] // [[CC::opt(1), CC::debug]]와 같음
[[using CC: CC::opt(1)]]   // error: using과 스코프 속성을 결합할 수 없음

속성 지정자의 모든 항목이 =로 시작하면, 그 속성 지정자는 대신 **주석(annotations)**을 도입해요. =로 시작하지 않는 속성과 =로 시작하는 주석은 같은 속성 지정자 안에서 섞일 수 없어요. (C++26부터)

동작 방식(Explanation)

속성은 GNU와 IBM의 언어 확장 __attribute__((...)), Microsoft 확장 __declspec() 같은 구현 정의 언어 확장을 위한 통일된 표준 문법을 제공해요.

속성은 C++ 프로그램의 거의 어디에나 쓸 수 있고, 타입, 변수, 함수, 이름, 코드 블록, 전체 번역 단위 등 거의 모든 것에 적용할 수 있어요. 다만 각 개별 속성은 구현이 허용하는 자리에서만 유효해요. [[expect_true]]if에만 쓸 수 있고 클래스 선언에는 쓸 수 없는 속성일 수 있고, [[omp::parallel()]]은 코드 블록이나 for 루프에 적용되지만 타입 int에는 적용되지 않는 속성일 수 있어요(이 두 속성은 가상의 예시예요. 표준 및 일부 비표준 속성은 아래 참고).

선언에서 속성은 선언 전체 앞과, 선언되는 실체의 이름 바로 뒤에 모두 나타날 수 있어요. 그 경우 결합돼요. 대부분의 다른 상황에서 속성은 바로 앞의 실체에 적용돼요.

alignas 지정자는 문법이 다르지만 속성 지정자 시퀀스의 일부예요. [[...]] 속성이 나타날 수 있는 자리에 나타날 수 있고, (허용되는 자리라면) 섞어 쓸 수도 있어요.

연속된 두 개의 왼쪽 대괄호 토큰([[)은 속성 지정자를 도입할 때나 속성 인자 안에서만 나타날 수 있어요.

void f()
{
    int y[3];
    y[[] { return 0; }()] = 1;  // error
    int i [[cats::meow([[]])]]; // OK
}

아래 나열된 표준 속성들 외에도, 구현은 구현 정의 동작을 가진 임의의 비표준 속성을 지원할 수 있어요. 구현이 모르는 모든 속성은 오류 없이 무시돼요. (C++17부터)

attribute-namespace가 없는 속성, 그리고 이름이 std이거나 std 뒤에 숫자가 하나 이상 붙은 attribute-namespace는 향후 표준화를 위해 예약돼 있어요. 즉, 모든 비표준 속성은 구현이 제공하는 attribute-namespace 안에 있어요. 예를 들어 [[gnu::may_alias]], [[clang::trivial_abi]], [[msvc::noop_dtor]] 같은 것들이에요. (C++20부터)

표준 속성(Standard attributes)

다음 속성들이 C++ 표준으로 정의돼 있어요.

표준 속성은 문법적으로 무시될 수 없어요. 즉, 문법 오류를 담을 수 없고, 올바른 대상에 적용돼야 하며, 인자의 실체는 odr-사용돼야 해요.

표준 속성은 의미상으로도 무시될 수 없어요. 특정 표준 속성의 모든 인스턴스를 제거한 동작이, 그 속성이 있는 원래 프로그램에 대한 적합한 동작(conforming behavior)이었을 것이기 때문이에요.

속성 의미
[[noreturn]](C++11) 함수가 반환하지 않음을 나타냄
[[carries_dependency]](C++11, C++26에서 제거) release-consume std::memory_order의 의존성 체인이 함수 안팎으로 전파됨을 나타냄
[[deprecated]] / [[deprecated("이유")]](C++14) 이 속성으로 선언된 이름이나 실체의 사용이 허용되지만, 어떤 이유로 권장되지 않음을 나타냄
[[fallthrough]](C++17) 이전 case 레이블에서의 낙하(fall through)가 의도적임을 나타내고, fall-through에 경고하는 컴파일러가 진단하지 않도록 함
[[maybe_unused]](C++17) 사용되지 않는 실체에 대한 컴파일러 경고를 (있는 경우) 억제함
[[nodiscard]] / [[nodiscard("이유")]](C++17, C++20) 반환 값이 버려지면 컴파일러가 경고를 내도록 권장함
[[likely]] / [[unlikely]](C++20) 문을 통과하는 실행 경로가 다른 경로보다 더(또는 덜) 가능성 있다고 생각하고 컴파일러가 최적화하도록 나타냄
[[no_unique_address]](C++20) 비정적 데이터 멤버가 자기 클래스의 다른 모든 비정적 데이터 멤버와 구별되는 주소를 가질 필요가 없음을 나타냄
[[assume(표현식)]](C++23) 주어진 지점에서 그 표현식이 항상 true로 평가될 것임을 명시함
[[indeterminate]](C++26) 초기화되지 않은 객체가 불확정 값(indeterminate value)을 가짐을 명시함
[[optimize_for_synchronized]](TM TS) 함수 정의가 synchronized 문에서의 호출에 최적화되어야 함을 나타냄

주의할 점(Notes)

각 개별 속성의 특정 플랫폼에서의 존재 여부는 __has_cpp_attribute 전처리기 매크로로 확인할 수 있어요.

기능 테스트 매크로 표준 기능
__cpp_attributes 200809L (C++11) Attributes
__cpp_namespace_attributes 201411L (C++17) 이름공간용 속성

예제

같은 속성들을 어떻게 여러 방식으로 선언할 수 있는지 볼게요.

[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]]
inline int f(); // 네 개의 속성으로 f 선언

[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]]
int f(); // 위와 같지만, 네 개의 속성을 담은 단일 속성 지정자를 사용

// C++17:
[[using gnu : const, always_inline, hot]] [[nodiscard]]
int f[[gnu::always_inline]](); // 속성은 여러 지정자에 나타날 수 있음

int f() { return 0; }

int main() {}

결함 보고(Defect reports)

이전에 발표된 C++ 표준들에 소급 적용된 동작 변경 결함 보고들이 있어요.

DR 적용 대상 발표 당시 동작 올바른 동작
CWG 2079 C++11 [[가 속성 인자 안에 나타날 수 없었음 허용됨
CWG 2538 C++11 표준 속성을 문법적으로 무시할 수 있는지가 불명확했음 금지됨
CWG 2695 C++11 표준 속성을 의미상으로 무시할 수 있는지가 불명확했음 금지됨
P2156R1 C++11 모든 표준 속성이 attribute-list에 최대 한 번 나타나야 했음 요구하지 않음

더 알아보기

  • __has_cpp_attribute: 속성의 존재 여부 확인.
  • GCC, Clang, MSVC의 속성 문서: 각 컴파일러가 제공하는 비표준 속성들.