[Dive into C++] Templates, Forwarding Reference, Perfect Forwarding, Data Type Deduction


Templates

  • Most of the cost for using templates is paid at compile time
  • A template is instantiated at compile time
    • create a cookie cutter, which is a class

Template Class with a Specialized Method

#include <iostream>

template <class T>  // "class" or "typename"
class Widget
{
public:
    void print()
    {
        std::cout << "generic print" << std::endl;
    }
};

template <>
void Widget<int>::print()
{
    std::cout << "specific print" << std::endl;
}

int main()
{
    Widget<float> widget1;
    widget1.print();

    Widget<int> widget2;
    widget2.print();
}

Template Class with a Templated Method

#include <iostream>

template<class T>  // "class" or "typename"
class Widget
{
public:
    template<class M>
    void print(M data);
};

// NOT specialization because no constraints on the T or M
template <class T>  // refers to the class
template <class M>  // refers to the method
void Widget<T>::print(M data)
{
    std::cout << data << std::endl;
}

// specialization!
template <>
template <>
void Widget<int>::print(int data)
{
    std::cout << "int:" << data << std::endl;
}

int main()
{
    Widget<void> widget1;
    widget1.print(0.1f);

    Widget<void> widget2;
    widget2.print(1);

    Widget<int> widget3;
    widget3.print(1);
}

Template Class with a Class Partial Specialization

#include <iostream>
#include <vector>

template <class T>
class Widget
{
public:
    Widget(T x) : data(x) {}
    void print()
    {
        std::cout << data << std::endl;
    }
private:
    T data;
};

// a class partial specialization
template <class X>
class Widget<std::vector<X>>  // notice this
{
public:
    Widget(std::vector<X> xs) : data(xs) {}

    void print()
    {
        for (auto& x : data) std::cout << x << " ";
        std::cout << std::endl;
    }
private:
    std::vector<X> data;
};

int main()
{
    Widget<int> widget1(1);  // T is int
    widget1.print();

    Widget<std::vector<int>> widget2({1, 2, 3});  // X is int
    widget2.print();
}

NOTE: Only templated classes may be partially specialized; templated methods must be fully specialized.

Variadic Templates, Parameter Pack

template<typename ... Ts>
class Widget;

Solve sum example:

template <typename T>
T adder(T first)
{
    return first;
}

template <typename T, typename ... Args>  // parameter pack Args
T adder(T first, Args ... args)    // parameter pack args
{
    return first + adder(args...);
}

int main()
{
    std::cout << adder(1, 2) << std::endl;
    std::cout << adder(1, 2, 4, 5) << std::endl;
}

Forwarding Reference

  • a declaration using data type of Widget &&
    • normally an rvalue reference
    • but it might not be if Widget is a template parameter or auto(the compiler has the option to discard one of the ampersands)
  • C++11 intentionally overloaded this syntax
    • the community made up a term of: universal reference
    • C++ committee has saind forwarding reference is a more accurate term

Perfect Forwarding

  • refers to a template function or method which passes arguments
    • to another function or method
    • preserving the const qualifier and lvalue/rvalue category
  • std::forward instead of std::move
    • std::move will force the value categary to rvalue
    • std::forward converts the value categary to rvalue only if the original argument was an rvalue

Data Type Deduction

  • templates
    • T and Parameter-Type may not be deduced as the same data type
    • Paramter-Type can include qualifiers like const or a reference
template<typename T>
void func(Parameter-Type var);

Examples

Deduce const:

template <typename T>
void func(T& var)
{
    // var is const int
}

int main()
{
    const int x = 666;
    func(x);
}

Forwarding reference:

template <typename T>
void func(T&& var)
{
}

int main()
{
    func(42);  // rvalue
    int x = 52;
    func(x);  // lvalue
}

References


Leave a Reply

Your email address will not be published. Required fields are marked *

css.php