Deducing Types

Template

template<typename T>
void f(T& param); // param is a reference
//and we have these variable declarations,
int x = 27; // x is an int
const int cx = x; // cx is a const int
const int& rx = x; // rx is a reference to x as a const int
//the deduced types for param and T in various calls are as follows:
f(x); // T is int, param's type is int&
f(cx); // T is const int,
 // param's type is const int&
f(rx); // T is const int,
 // param's type is const int&

universal reference

template<typename T>
void f(T&& param); // param is now a universal reference
int x = 27; // as before
const int cx = x; // as before
const int& rx = x; // as before
f(x); // x is lvalue, so T is int&, param's type is also int&
f(cx); // cx is lvalue, so T is const int&, param's type is also const int&
f(rx); // rx is lvalue, so T is const int&, param's type is also const int&
f(27); // 27 is rvalue, so T is int,param's type is therefore int&&

not pointer or reference

template<typename T>
void f(T param); // param is now passed by value
int x = 27; // as before
const int cx = x; // as before
const int& rx = x; // as before
f(x); // T's and param's types are both int
f(cx); // T's and param's types are again both int
f(rx); // T's and param's types are still both int
template<typename T>
void f(T param); // param is still passed by value
const char* const ptr = // ptr is const pointer to const object "Fun with pointers";
f(ptr); // pass arg of type const char * const

Array Arguments

template<typename T, std::size_t N> // see info
constexpr std::size_t arraySize(T (&)[N]) noexcept // below on
{
    return N; // and
} 
int keyVals[] = { 1, 3, 7, 9, 11, 22, 35 }; // keyVals has 7 elements
int mappedVals[arraySize(keyVals)]; // so does mappedVals

Auto

auto x = 27; // case 3 (x is neither ptr nor reference)
const auto cx = x; // case 3 (cx isn't either)
const auto& rx = x; // case 1 (rx is a non-universal ref.)
auto&& uref1 = x; // x is int and lvalue,  so uref1's type is int&
auto&& uref2 = cx; // cx is const int and lvalue,  so uref2's type is const int&
auto&& uref3 = 27; // 27 is int and rvalue,  so uref3's type is int&&
const char name[] ="R. N. Briggs"; // name's type is const char[13]
auto arr1 = name; // arr1's type is const char*
auto& arr2 = name; // arr2's type is
void someFunc(int, double); // someFunc is a function;  type is void(int, double)
auto func1 = someFunc; // func1's type is void (*)(int, double)
auto& func2 = someFunc; // func2's type is void (&)(int, double)
auto x5 = { 1, 2, 3.0 }; // error! can't deduce T for std::initializer_list<T>

Decltype

const int i = 0; // decltype(i) is const int
bool f(const Widget& w); // decltype(w) is const Widget& decltype(f) is bool(const Widget&)
struct Point {
 int x, y; // decltype(Point::x) is int
}; // decltype(Point::y) is int
Widget w; // decltype(w) is Widget
if (f(w)) … // decltype(f(w)) is bool
template<typename T> // simplified version of std::vector
class vector {
public:
 …
 T& operator[](std::size_t index);
 …
};
vector<int> v; // decltype(v) is vector<int>
…
if (v[0] == 0) … // decltype(v[0]) is int&
template<typename Container, typename Index> // works, but requires refinement
auto authAndAccess(Container& c, Index i) -> decltype(c[i]) 
{
 authenticateUser();
 return c[i];
}
template<typename Container, typename Index> // C++14;
auto authAndAccess(Container& c, Index i) // not quite
{ // correct
 authenticateUser();
 return c[i]; // return type deduced from c[i]
}
std::deque<int> d;
…
authAndAccess(d, 5) = 10; // authenticate user, return d[5],
 // then assign 10 to it;
// this won't compile!

template<typename Container, typename Index> // C++14; works,but still requires refinement
decltype(auto) 
authAndAccess(Container& c, Index i) 
{ 
 authenticateUser();
 return c[i];
}

Widget w;
const Widget& cw = w;
auto myWidget1 = cw; // auto type deduction: myWidget1's type is Widget
decltype(auto) myWidget2 = cw; // decltype type deduction: myWidget2's type 
    int i=12;
    decltype(i) ii=i;//value
    decltype((i)) iii=i;//reference
    decltype(auto) iiii=i;//reference
decltype(auto) f1()
{
 int x = 0;
 …
 return x; // decltype(x) is int, so f1 returns int
}
decltype(auto) f2()
{
 int x = 0;
 …
 return (x); // decltype((x)) is int&, so f2 returns int&
}

why auto

template<typename It> // algorithm to dwim ("do what I mean")
void dwim(It b, It e) // for all elements in range from
{ // b to e
 while (b != e) {
 typename std::iterator_traits<It>::value_type currValue = *b;
 }
}

and you can use auto instead

template<typename It> // as before
void dwim(It b, It e)
{
 while (b != e) {
 auto currValue = *b;
 …
 }
auto derefUPLess = // comparison func.
 [](const std::unique_ptr<Widget>& p1, // for Widgets
 const std::unique_ptr<Widget>& p2) // pointed to by
 { return *p1 < *p2; }; // std::unique_ptrs
//use auto for all 
auto derefLess = // C++14 comparison
 [](const auto& p1, // function for
 const auto& p2) // values pointed
 { return *p1 < *p2; }; // to by anything
 // pointer-like

CONSTEXPR

Declare functions noexcept if they won’t emit exceptions

Values known during compilation are privileged. They may be placed in read-only memory, for example, and, especially for developers of embedded systems, this can be a feature of considerable importance. Of broader applicability is that integral val‐ ues that are constant and known during compilation can be used in contexts where C++ requires an integral constant expression. Such contexts include specification of array sizes, integral template arguments (including lengths of std::array objects), enumerator values, alignment specifiers, and more. If you want to use a variable for these kinds of things, you certainly want to declare it constexpr, because then com‐ pilers will ensure that it has a compile-time value:

int sz; // non-constexpr variable … 
constexpr auto arraySize1 = sz; // error! sz's value not known at compilation 
std::array data1; // error! same problem 
constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr

Note that const doesn’t offer the same guarantee as constexpr, because const
objects need not be initialized with values known during compilation:

int sz; // as before
…
const auto arraySize = sz; // fine, arraySize is const copy of sz
std::array<int, arraySize> data; // error! arraySize's value not known at compilation

Simply put, all constexpr objects are const, but not all const objects are constexpr.
If you want compilers to guarantee that a variable has a value that can beused in contexts requiring compile-time constants, the tool to reach for is constexpr, not const.

constexpr functions can be used in contexts that demand compile-time con‐
stants. If the values of the arguments you pass to a constexpr function in such a context are known during compilation, the result will be computed during compilation. If any of the arguments’ values is not known during compilation,your code will be rejected.

When a constexpr function is called with one or more values that are not
known during compilation, it acts like a normal function, computing its result at runtime. This means you don’t need two functions to perform the same operation, one for compile-time constants and one for all other values. The constexpr function does it all.

constexpr // pow's a constexpr func
int pow(int base, int exp) noexcept // that never throws
{
 … // impl is below
}
constexpr auto numConds = 5; // # of conditions
std::array<int, pow(3, numConds)> results; // results has 3^numConds elements
auto base = readFromDB("base"); // get these values
auto exp = readFromDB("exponent"); // at runtime
auto baseToExp = pow(base, exp); // call pow function at runtime
constexpr int pow(int base, int exp) noexcept
{
 return (exp == 0 ? 1 : base * pow(base, exp - 1));
}

constexpr functions are limited to taking and returning literal types, which essentially means types that can have values determined during compilation. In C++11, all built-in types except void qualify, but user-defined types may be literal, too, because constructors and other member functions may be constexpr:

class Point {
public:
 constexpr Point(double xVal = 0, double yVal = 0) noexcept
 : x(xVal), y(yVal)
 {}
 constexpr double xValue() const noexcept { return x; }
 constexpr double yValue() const noexcept { return y; }
 void setX(double newX) noexcept { x = newX; }
 void setY(double newY) noexcept { y = newY; }
private:
 double x, y;
};
constexpr Point p1(9.4, 27.7); // fine, "runs" constexpr ctor during compilation
constexpr
Point midpoint(const Point& p1, const Point& p2) noexcept
{
 return { (p1.xValue() + p2.xValue()) / 2, // call constexpr
 (p1.yValue() + p2.yValue()) / 2 }; // member funcs
}
constexpr auto mid = midpoint(p1, p2); // init constexpr object w/result of constexpr function

In C++11, two restrictions prevent Point’s member functions setX and setY from being declared constexpr. First, they modify the object they operate on, and in C++11, constexpr member functions are implicitly const. Second, they have void return types, and void isn’t a literal type in C++11. Both these restrictions are lifted in C++14, so in C++14, even Point’s setters can be constexpr:

class Point {
public:
 …
 constexpr void setX(double newX) noexcept // C++14
 { x = newX; }
 constexpr void setY(double newY) noexcept // C++14
 { y = newY; }
 …
};
constexpr Point reflection(const Point& p) noexcept
{
 Point result; // create non-const Point
 result.setX(-p.xValue()); // set its x and y values
 result.setY(-p.yValue());
 return result; // return copy of it
}
constexpr Point p1(9.4, 27.7); // as above
constexpr Point p2(28.8, 5.3);
constexpr auto mid = midpoint(p1, p2);
constexpr auto reflectedMid = // reflectedMid's value is
 reflection(mid); // (-19.1 -16.5) and known  during compilation