Jul 15, 2017

[C++] unnamed variable

Reference:
https://www.reddit.com/r/cpp/comments/6mzxsf/c_unnamed_programming/
http://nosubstance.me/post/cpp-unnamed-programming/
https://cplusplus.github.io/EWG/ewg-active.html#35
https://github.com/jeaye/value-category-cheatsheet/blob/master/value-category-cheatsheet.pdf
http://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary
https://stackoverflow.com/questions/39279074/what-does-the-void-in-decltypevoid-mean-exactly


Unnamed variable.
Used for, i.e,
    std::lock_guard
    constructor that takes only l-value but no r-value. (i.e, an unnamed pr-value object can't be used)


First attempt:
    Evaluation order is NOT guaranteed.

#include <mutex>

namespace detail {
    template<typename First>
    decltype(auto) select_last(First& first) {
        return first;
    }

    // Returns a lvalue reference to the last element.
    template<typename First, typename... Rest>
    decltype(auto) select_last(First&, Rest&... rest) {
        return select_last(rest...);
    }
}

// Takes a number of arguments and invokes the last one as a function.
// Ignores all other arguments.
template<typename... T>
void with(T&&... objects) {
    auto& fn = detail::select_last(objects...);
    fn();
}

int g_i = 0;
std::mutex g_mutex;

int main() {
    with(std::lock_guard<std::mutex>(g_mutex),
        [&]() {
            ++g_i;
        }
    );
} 

Thus, second attempt:
    Using , operator

void safe_increment() {
    std::lock_guard<std::mutex>{g_i_mutex}, ++g_i;
}

Using void type constructor to avoid user defined type , operator overload.
i.e, void() type instance is a void object.
what-does-the-void-in-decltypevoid-mean-exactly

void(UDT("1")), void(UDT("2")), [] {
    cout << "hello" << endl;
}();

Make a pr-value object a l-value:
    Be aware that the pr-value will dangle after complete the function call expression.
 
    Initializing the parameter of type int&& a temporary object of value 42 is created ([dcl.init.ref]/(5.2.2.2)),
    the temporary object persists until the completion of the full-expression containing the call ([class.temporary]/(5.2)).

template <typename T>
constexpr T& lvalue(T &&r) noexcept { return r; }  // return l-value

usage:

vector<char> data(
    istreambuf_iterator<char>(lvalue(ifstream("file.dat", ios::binary))),
    {});

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.