2

Variadic Templates

  • 谈的是 template

    • function template
    • class template
  • 变化的是 template parameter

    • 参数个数(variable number)

      • 利用参数个数递减的特性,实现递归函数调用。使用 function template完成
    • 参数类型(different type)

      • 利用参数个数逐一递减导致参数类型也逐一递减的特性实现递归继承或递归复合,以class template 完成。
void func() 
{
    /* ... */
}

template <typename T, typename ... Types>
void func(const T & firstArg, const Types &...args)
{
    // 处理 firstArg
    
    func(args...);
}

示例一

since C++11, template can have parameters that accept a variable number of template arguments. This ability is called variadic template. For example, you can use the following to call printX() for a aviable number of argument of diferent types.

(从C ++ 11开始,模板可以具有接受可变数量的模板参数的参数。 此功能称为可变参数模板。 例如,你可以使用以下代码为不同类型的大量参数调用printX()。)

文件:Test.cpp

#include <iostream>
#include <bitset>

using namespace std;

void printX()
{ }

template <typename T, typename ...Type>
void printX(const T &firstArg, const Type &...args)
{
    cout << sizeof...(args) << " "<< firstArg << endl;

    printX(args...);
}

int main()
{
    printX(7.5, "hello", bitset<16>(377), 42);

    return 0;
}

输出:

3 7.5
2 hello
1 0000000101111001
0 42
If one or more arguments are passed, the function template is used, which by specifying the first argument separately allows the first argument to print and then recursively calls printX() for the remaining argument. To end the recursion, the non-template overload of printX() is provided.

(如果传递了一个或多个参数,则使用函数模板,通过分别指定第一个参数,可以打印第一个参数,然后递归地为其余参数调用printX()。为了结束递归,提供了printX()的非模板重载。)

示例二

使用 variadic template 重写 printf()

文件:Test.cpp

#include <iostream>

namespace T
{

void printf(const char *s)
{
    while (*s)
    {
        if ((*s == '%') && (*(++s) != '%'))
            throw std::runtime_error("invalid format string: missing argument");

        std::cout << *s++;
    }
}

template <typename T, typename ...Args>
void printf(const char *s, T value, Args ...args)
{
    while (*s)
    {
        if ((*s == '%') && (*(++s) != '%'))
        {
            std::cout << value;

            printf(++s, args...);

            return;
        }

        std::cout << *s++;
    }

    throw std::logic_error("extra argument provided to printf");
}

}

int main()
{
    int *pi = new int{};

    T::printf("%d %s %p %f\n", 15, "This is Ace", pi, 3.1415926);

    delete pi;

    return 0;
}

示例三

文件:Test.cpp

#include <iostream>

using namespace std;

struct _Iter_less_iter
{
    template<typename _Iterator1, typename _Iterator2>

    bool operator() (_Iterator1 __it1, _Iterator2 __it2) const
    {
        return *__it1 < *__it2;
    }
};

inline _Iter_less_iter __iter_less_iter()
{
    return _Iter_less_iter();  // 临时对象
}

template <typename _ForwardIterator, typename _Compare>
_ForwardIterator __max_element(_ForwardIterator __first,
                               _ForwardIterator __last,
                               _Compare __comp)
{
    if (__first == __last)
        return __first;

    _ForwardIterator __result = __first;

    while (++__first != __last)
        if (__comp(__result, __first))
            __result = __first;

    return __result;
}

template <typename _ForwardIterator>
inline _ForwardIterator max_element(_ForwardIterator __first,
                                    _ForwardIterator __last)
{
    return __max_element(__first, __last, __iter_less_iter());
}

template <typename _Tp>
inline _Tp max(initializer_list<_Tp> __l)
{
    return *max_element(__l.begin(), __l.end());
}

int main()
{
    cout << max({57, 48, 60, 100, 20, 18}) << endl;

    return 0;
}

若参数类型都相同,则无需使用 variadic templates, 使用 initializer_list<T> 足够。

示例四

#include <iostream>

using namespace std;

namespace T
{

template <typename T>
T max(T value)
{
    return value;
}

template <typename T>
T max(T lh, T rh)
{
    return lh > rh ? lh : rh;
}

template <typename T, typename ...Args>
T max(T value, Args ...args)
{
    return max(value, max(args...));
}

}

int main()
{
    cout << T::max(57, 48, 60, 100, 20, 18) << endl;

    return 0;
}

示例五

  • 以异于一般的方式处理 first 元素和 last 元素

文件:Test.cpp

#include <iostream>
#include <tuple>
#include <string>
#include <bitset>

using namespace std;

template <int IDX, int MAX, typename ...Args>
struct PRINT_TUPLE
{
    static void print(std::ostream &os, const tuple<Args...> &t)
    {
        os << get<IDX>(t) << (IDX+1==MAX ? "" : ",");

        PRINT_TUPLE<IDX+1, MAX, Args...>::print(os, t);
    }
};

// 特化实现,递归出口
template <int MAX, typename ...Args>
struct PRINT_TUPLE <MAX, MAX, Args...>
{
    static void print(ostream &os, const tuple<Args...> &t)
    { }
};

//--------
template <typename ...Args>
ostream &operator << (ostream &os, const tuple<Args...> &t)
{
    cout << "[";
    PRINT_TUPLE<0, sizeof...(Args), Args...>::print(os, t);
    cout << "]";

    return os;
}

int main()
{
    cout << make_tuple(7.5, string("hello"), bitset<16>(377), 42) << endl;

    return 0;
}

输出:

[7.5,hello,0000000101111001,42]

示例六

  • 用于递归继承,recursive inheritance

文件:Test.cpp

#include <iostream>
#include <string>

using namespace std;

namespace T
{

// 泛型
template <typename ...Value>
class tuple;

// 特化出口
template <>
class tuple <>
{ };

// 特化
template <typename Head, typename ...Tail>
class tuple<Head, Tail...> : private tuple<Tail...>  // 私有继承,表明两类之间不是 ‘isa’ ,仅是内存继承关机
{
    typedef tuple<Tail...> inherited;  // using inherited=tuple<Tail...>;

public:
    tuple()
    { }

    tuple(Head v, Tail... vtail) : inherited(vtail...), m_head(v)
    { }

    Head head()
    {
        return m_head;
    }

    inherited& tail()
    {
        return *this;
    }

protected:
    Head m_head;
};

}

int main()
{
    T::tuple<int, float, string> t(41, 6.3f, "nico");

    cout << t.head() << endl;
    cout << t.tail().head() << endl;
    cout << t.tail().tail().head() << endl;

    return 0;
}

输出:

41
6.3
nico
  • 层析分解

1_meitu_1.jpg

  • 内存布局

2_meitu_2.jpg

示例七

  • 用于递归复合,recursive composition

文件:Test.cpp

#include <iostream>
#include <string>

using namespace std;

namespace T
{

// 泛化
template <typename ...Value>
class tuple;

// 特化出口
template <>
class tuple <>
{ };

// 特化
template <typename Head, typename ...Tail>
class tuple <Head, Tail...>
{
    typedef tuple<Tail...> composited;  // using composited = tuple<Tail...>;

public:
    tuple()
    { }

    tuple(Head v, Tail... vtail) : m_tail(vtail...), m_head(v)
    { }

    Head head()
    {
        return m_head;
    }

    composited& tail()
    {
        return m_tail;
    }

protected:
    composited m_tail;
    Head m_head;
};

}

int main()
{
    T::tuple<int, float, string> t(41, 6.3f, "nico");

    cout << t.head() << endl;
    cout << t.tail().head() << endl;
    cout << t.tail().tail().head() << endl;

    return 0;
}

输出:

41
6.3
nico
  • 递归调用,处理的是参数,使用 function template
  • 递归符合,处理的是类型,使用 class template

C++ 关键字

image.png


TianSong
734 声望138 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧