Skip to content
Takatoshi Kondo edited this page Jan 22, 2022 · 17 revisions

Case, Spacing, braces position, and so on.

#define SNAKE_CASE (1)

namespace snake_case {

//             east const
constexpr char const snake_case  = 0b00000010;

template <typename UpperCamelCase>
class snake_case {
public:
    void snake_case() {
        if (condition1) { // whitespace after if and between ) and {
            // ...
        }
        else {            // don't } else { 
            // ...
        }

        switch (condition2) {
        case 1:           // case indent level is same as switch
            // ...
            break;
        case 2:
            // ...
            break;
        case 3: {
            int local_variable = 1;
            // ...
        } break;
        }

        // whitespace after for , & is connected with type not variable, whitespace before and after :
        for (auto const& e : collection) { 
        }
    }

    template <typename SomethingLong>
    std::enable_if_t< // std::enable_if_t is C++14 feature. Use it instead of typename std::enable_if<...>::type
        std::is_same< // if the parameters are long, then use this type multi line indent.
            SomethingLong,
            int
        >::value // std::is_same_v is C++17 feature. Don't use it.
    >
    multi_line_function_template(SomethingLong v) {
        // ...
    }

private:
    int snake_case_; // underscore postfix
};

} // namespace snake_case

Indent is four spaces, please don't use TAB.

Don't use negative comparison with else.

If condition has an else clause, condition should be positive. This rule is applied not only MACRO but also normal if-else.

// OK
#if defined(SOME_CONDITION)
    // do A
#else  // defined(SOME_CONDITION)
    // do B
#endif // defined(SOME_CONDITION)

// NG
#if !defined(SOME_CONDITION)
    // do B
#else  // !defined(SOME_CONDITION)
    // do A
#endif // !defined(SOME_CONDITION)

Conditional operator vs Lambda expression

Immediate invoking lambda expression is more preferred than conditional operator. If the types of return values are different, the lambda expression can declare the return type explicitly.

auto r = 
    [&]() -> int {
        if (cond1 == 0) {
            if (cond2 == 0) {
                return 100;
            }
            return 200;
        }
        return 300;
    } ();

Equivalent conditional operator. It is complicated.

int r = cond1 == 0 ? cond2 == 0 ? 100
                                : 200
                   : 300;

If the expression is simple enough, you can use conditional operator.

Details of lambda expression

If the lambda expression has long capture list and/or long parameter list, write as follows:

auto lambda =
    [.................](.................) {
    };

// or

auto lambda =
    [.................]
    (.................) {
    };

If the lambda expression is called in the function, then you can use [&] capture.

void foo() {
    auto lambda = [&] {};
    // ...
    lambda();
}

However, if the lambda expression is called after the function is finished, then you need to use explicit capture list. It is typical situation on asynchronous API callback.

void foo(int& i) {
    auto lambda = [&i] {};
    // ...
    as::post(ioc, lambda);
}

Choosing variable type policy

Please respect the order.

  1. Basically use the value. foo f;.
  2. If the value should be nullable, then use MQTT_NS::optional. MQTT_NS::optional<foo> f. In order to lazy initalize, use f.emplace(...).
  3. If there is convincible reason to locate the value to the heap, then use std::unique_ptr<foo> f. Don't use std::shared_ptr<foo>.
  4. If and only if reference counting pattern is required, then use std::shared_ptr<foo> f.

Writing JSON

Please use this formatting rule for JSON

  1. User four white spaces to indent.
  2. Insert one white space after :.
  3. Use one line to add , between objects. It helps copy and paste.
{
    "key1": [
        {
            "subkey1": "value1",
            "subkey2": ["value2-1", "value2-2"]
        }
        ,
        {
            "subkey1": "value1",
            "subkey2": ["value2-1", "value2-2"]
        }
    ]
    ,
    "key2": [
        {
            "subkey1": "value1",
            "subkey2": ["value2-1", "value2-2"]
        }
    ]
}

When you insert JSON to the C++ code, please use raw string literals as follows:

void foo() {
    std::string json_str = R"*(
{
    "key1": [
        {
            "subkey1": "value1",
            "subkey2": ["value2-1", "value2-2"]
        }
    ]
}
)*";
    std::cout << json_str << std::endl;
}

auth.json example:

{
    "authentication": [
        {
            "name": "u1",
            "method": "sha256",
            "salt": "salt",
            "digest": "694073aa885f21f4dc23af70b5d2d30dc115dcfc0c5661113ca8bab2373d741d"
        }
        ,
        {
            "name": "u2",
            "method": "client_cert",
            "field": "CNAME"
        }
        ,
        {
            "name": "u2",
            "method": "plain_password",
            "password": "mypassword"
        }
        ,
        {
            "name": "anonymous",
            "method": "anonymous"
        }
    ]
    ,
    "group": [
        {
            "name": "@g1",
            "members": ["u1", "u2", "anonymous" ]
        }
    ]
    ,
    "authorization": [
        {
            "topic": "#",
            "type": "allow",
            "pub": ["@g1"]
        }
        ,
        {
            "topic": "#",
            "type": "deny",
            "sub": ["@g1"]
        }
        ,
        {
            "topic": "sub/#",
            "type": "allow",
            "sub": ["@g1"],
            "pub": ["@g1"]
        }
        ,
        {
            "topic": "sub/topic1",
            "type": "deny",
            "sub": ["u1", "anonymous"],
            "pub": ["u1", "anonymous"]
        }
    ]
}

When