Attributes?

Preprocessor macros introduced after c++11. These allows user to pass information to complier for various purposes. Examples:
- Code optimization, enforce constraints(conditions) on code, do some specific code generation you cannot define your own attributes. Attributes are given standard values which can be expanded using __has_cpp_attribute( attribute-token ) C++20.

attribute-token   |         Attribute        |  Value     | Standard 
--------------------|--------------------------|------------|------------
carries_dependency  | `[[carries_dependency]]` |  200809L   |	(C++11) 
deprecated          | `[[deprecated]]`         | 201309L    | (C++14) 
    fallthrough       |     `[[fallthrough]]`    | 201603L    | (C++17) 
    likely          |     `[[likely]]`         |  201803L   | (C++20)
    maybe_unused    |   `[[maybe_unused]]`     |  201603L   | (C++17)
    no_unique_address |   `[[no_unique_address]]`|  201803L	  | (C++20)
    nodiscard         |	  `[[nodiscard]]`        | 201603L, 201907L | (C++17), (C++20)
    noreturn          |   `[[noreturn]]`         |  200809L   | (C++11)
    unlikely          |   `[[unlikely]]`         |  201803L   |	(C++20)
        

Types of Attributes

Name Meaning Usage
carries_dependency Tells complier to skip unnecessary memory fence instructions for this function as it will consumes/releases memory being part atomic operation.
deprecated function would be deprecated

[[deprecated("Use addTemplated(int,int) instead")]]
int add(int a, int b){return a+b;}
int main(){
        cout << add(1,2);
}
# g++ test.cpp                //Gets complied but with warning
    : warning: ‘int add(int, int)’ is deprecated: Use addTemplated(int,int) instead [-Wdeprecated-declarations]
                    
[[fallthrough]] only with switch Indicates that the fall through from the previous case label is intentional & compiler should not throw warning. fallthrough can only be used with switch statement.

/////Code generating warning ////
void fun(int n) {
    switch (n) {
    case 1:
        cout << "1"
    default:
        cout << "default";
    }
}
int main(){
    fun(1);
}
$ g++ fallthru.cpp -Wimplicit-fallthrough
test.cpp: In function ‘void f(int)’:
test.cpp:11:15: warning: this statement may fall through [-Wimplicit-fallthrough=]
    2 |    cout << "1"

///////Code not generating warning//////////
void fun(int n) {
    switch (n) {
    case 1:
        cout << "1";
    [[fallthrough]];
    default:
        cout << "default";
    }
}
int main(){
    fun(1);
}
                
likely, unlikely These are Branch prediction macros, Can be applied to labels or statements.
[[likely]]: When applied to statement, tells that path of execution to this statement is more likely to be hit and complier should optimize for same.
[[unlikely]]: When applied to statement, tells that path of execution to this statement is less likely to be hit and complier should optimize for same.

///**C Implementation:** These are defined as follows in linux kernel code.///
http://lxr.linux.no/linux+v3.6.5/include/linux/compiler.h
#define likely(x)      __builtin_expect(!!(x), 1) 
#define unlikely(x)    __builtin_expect(!!(x), 0) 

- Example:
    - Here, if condition is marked likely. 
    - Compiler will optimize the program considering if is very likely to be hit.
    - If prediction is correct, it means there is zero cycle of jump instruction
    - but if prediction is wrong, then it will take several cycles, because processor needs to flush it’s pipeline

const char *home_dir ; 
home_dir = getenv("HOME"); 
if (likely(home_dir))  
    printf("home directory: %s\n", home_dir); 
else
    perror("getenv"); 
                
[[nodiscard]](C++17) [[nodiscard("reason")]](C++20) Compiler will issue a warning if return value is discarded from nodiscard function.
Where nodicard can be used? Function declaration, Enumeration declaration, class declaration

//////////////////////////FUNCTION DECLARATION///////////////////
[[nodiscard]] int f(){
    return 1;
}
int main(){
    f();
}
$ g++ nodiscard.cpp
test.cpp: In function ‘int main()’:
test.cpp:9:3: warning: ignoring return value of ‘int f()’, declared with attribute nodiscard [-Wunused-result]
    9 |  f();
        |  ~^~
                
noreturn - Indicates function will never returns to caller. This means function either throw an exception or call std::terminate.
- The behavior is undefined if the function with this attribute actually returns.
- Advantage Complier will not do clean up tasks(pushing rbp etc) and can optimize the function's code.

[[noreturn]] void fun(std::string message) {
    cout << message;
    if (THROW_EXCEPTION_ON_ASSERT)
        throw AssertException(std::move(message));
    terminate();
}
                
[[no_unique_address]] C++20 - Can only be applied to non-static data member of class/struct.
- Indicates that this data member need not have an seperate address from all other non-static data members of its class.
- But its implementation/compiler dependent not guranteed. For example: if member is Empty type compiler may optimize to occupy NO SPACE(same as in empty base).

struct inner {};
class A{
    int var;
    [[no_unique_address]] inner i1,i2;
public:
    void f(){
    cout << "i1=" << addressof(i1);
    cout << "i2=" << addressof(i2);
    }
};

int main(){
    A a;
    a.f();
}