Aug 10, 2014

[C++11][note] C++11 Library Design

Excerpt from Aerix Consulting

Study notes:

1. Function Interface Design

Is my function? :
  • easy to call correctly?
  • hard to call incorrectly?
  • efficient to call?
  • with minimal copying?
  • with minimal aliasing?
  • without unnecessary resource allocation?
  • easily composable with other functions?
  • usable in higher-order constructs?
What’s the best way of getting data into and out of a function?
  • Input Argument Categories
    • Read-only: value is only ever read from, never modified or stored
      • const l-ref (except small ones)
    • Sink: value is consumed, stored, or mutated locally
      • Goal: Avoid unnecessary copies, allow temporaries to be moved in.
        • const l-ref and copy it into local variable
        • r-ref. Take the r-value into function.
      • What if the function takes more than 1 sink argument?
        • Take sink arguments by value.
          Since if passing in r-value, the r-value will be created as the l-value argument.
          No extra copy constructor call needed. (extra reference: WANT SPEED? DON’T (ALWAYS) PASS BY VALUE.)
    • Eric Niebler : Out Parameters, Move Semantics, and Stateful Algorithms
    • Encapsulate an algorithm’s state in an object that implements the algorithm.
2. Class Design
Can my type be…?:
  • …copied and assigned?
  • …efficiently passed and returned?
  • …efficiently inserted into a vector?
  • …sorted?
  • …used in a map? An unordered_map?
  • …iterated over (if it’s a collection)?
  • …streamed?
  • …used to declare global constants?

  • Regular Types
    • Reference:
    • Basically, int-like types.
    • Copyable, default constructable, assignable, equality-comparable, swappable, order-able
    • They let us reason mathematically
    • The STL containers and algorithms assume regularity in many places
    • Make your types regular (if possible)
    • **Make your types’ move operations noexcept (if possible)
    • Q: Is my type Regular?
      A: Check it at compile time!
template<typename T>
struct is_regular
: std::integral_constant< bool,
std::is_default_constructible<T>::value &&
std::is_copy_constructible<T>::value &&
std::is_move_constructible<T>::value &&
std::is_copy_assignable<T>::value &&
std::is_move_assignable<T>::value >
{};
struct T {};
static_assert(is_regular<T>::value, "huh?");


Movable Types:
  • The moved-from state must be part of a class’s invariant.
  • If above doesn’t make sense, the type isn’t movable.
  • Every movable type must have a cheap(er)-to-construct, valid default state.


3. Module
Think:
  • In C++11, what support is there for…
  • … enforcing acyclic, hierarchical physical component dependencies? 
  • … decomposing large components into smaller ones? 
  • … achieving extensibility of components? 
  • … versioning (source & binary) components?
New library version with interface-breaking changes:


  • Put all interface elements in a versioning namespace from day one
  • Make the current version namespace inline

Name Hijacking: Unintentional ADL finds the wrong overload:
  • template arguments are participating ADL.

ADL:
If the class is a class template instantiation, then the types of the template type arguments and the classes and namespaces in which the template template arguments are declared are also included.

Solution:
1. Use a non-inline ADL-blocking namespace
2. Use global function objects instead of free functions(i.e: Global function object, aka. functor)




C++14 Variable Templates:
cpp14_variable_templates

template<typename T> struct lexical_cast_fn 
{ 
template<typename U> T operator()(U const &u) const 
{ //... } 
};

template<typename T> constexpr lexical_cast_fn<T> lexical_cast{};

int main()
{ 
lexical_cast<int>("42");
}


Ode To Function Objects:
  • They are never found by ADL!
  • If phase 1 lookup finds an object instead of a function, ADL is disabled!
  • They are first class objects
  • Easy to bind
  • Easy to pass to higher-order functions like std::accumulate

Guideline:
  • Put type definitions in an ADL-blocking (non-inline!)
    namespaces and export then with a using declaration, or…
  • Prefer global constexpr function objects over named free functions (except for documented customization points)

No comments:

Post a Comment

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