May 27, 2018

[C++][accu2018] Tricks library implementation to know


Also refer to:


1. EBO(Empty base class optimizations)

Put interface into base type, which does not have data members.

Every derived types use the same interface without cost.(i.e extra memory alignment, iff not virtual)
There are some interesting/useful attribute in C++20:
  • likely
  • unlikely
  • no_unique_address
std::is_empty remember that bit fields of length 0 actually used to separate data member memory location.
(Ref: 

Definition of empty type:
a non-union class type with no non-static data members other than bit-fields of size 0, no virtual functions, no virtual base classes, and no non-empty base classes.

Mark [no_unique_address] if the data member has the empty type.

Why is marking [no_unique_address] important?
Consider about unique_ptr's deleter, it's a stateless type, but in order to save it, it takes up 1 byte, but it has no state!
Thus, mark it as [no_unique_address], if needed, type is just another namespace to access the member function.
(Ref:



2. Constrining greedy templates

i.e Don't be over generic
(Book: C++ template complete guide, ch.7.6)
Put a SFINAE constraint on deduced function/member function.

(Ref: 


std::remove_cvref (C++20) instead of using std::decay

For libstd++/libc++, were not using the latest feature due to backward compatibility.



3. Using common_type_t<T> as an identity meta-function

std::common_type

common_type_t is useful to create a non-deduced context.
(or use type_identity in C++20)

e.g
template<typename T>

void frob(std::vector<T>& a, T b){

    for (auto& c: a) {

        c *= b;

    }

}



std::vector<long> a{1,2,3};

frob(a, 5);


//error: no matching function for call to

//frob(std::vector<long int>&, int)



i.e T is long and int!

fix:
template<typename T>

void frob(std::vector<T>& a, typename type_identity<T>::type b);


or...
template<typename T>

void frob(std::vector<T>& a, std::common_type_t<T> b);



Above means that the second argument we do NOT want to deduce, but using our type explicitly.



4. Conditionally deleted special members

  • When having generic wrapper like std::optional
    we would want the wrapper type to model the same interface as the object it contains.
  • If is_copy_constructible<T> is false then we want is_copy_constructible<optional<T>> to be false.
  • if is_default_constructible<T> is false then is_default_constructible<optional<T>> is false as well.
How?
templatenize the member function and SFINAE.
(Ref: http://vsdmars.blogspot.com/2017/09/c-write-our-own-type-trait.html )

If finding compiler is fighting us over, using default/delete then.

Again, how?
Inheritance :-)
Move problem to base type.

template<typename T>
struct optional : maybe_copyable<is_copy_constructible_t<T>>
{
    optional(const optional&) = default;
};

template<bool IsCopyable>
struct maybe_copyable{};

// SMART...
template<>
struct maybe_copyable<false> {
    maybe_copyable(const maybe_copyable&) = delete;
};




5. Conditionally explicit constructors

explicit specifier

e.g
void sink(unique_ptr<X>);
void bath(pair<unique_ptr<X>, int>);
X x;
sink(&x); // fail
bath({&x, 1});  // uh-oh~ pass!




6. Using unique_ptr for exception safety 

don't do this, the legacy no-no in c++98:
void no_no(new int(2), new int(3));
use unique_ptr to the rescue:
unique_ptr<int> arg1(new int(3));
unique_ptr<int> arg2(new int(4));

void yeah_yeah(arg1.release(), arg2.release());
std::unique_ptr::release
(Ref: https://cplusplusmusings.wordpress.com/2015/03/09/simplifying-code-and-achieving-exception-safety-using-unique_ptr/ )



7. allocator_construct

std::allocator
(ref: http://vsdmars.blogspot.com/2017/10/c-allocator-template-code.html )

By providing our own allocator, we could:
  • log object creation/destruction
  • register/deregister objects in global registry
  • insert/ignore/change/rearrange constructor arguments.
  • decide what's the default value for the objects created by the allocator.



8. tag dispatch

read:



We can use
if constexpr
instead of tag dispatch in C++17, which reduce writing specialized tag dispatch/overload functions.

~fin~

No comments:

Post a Comment

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