C++ Templates

【C++ Templates(15)】特化与重载

2018-05-30  本文已影响20人  downdemo

当泛型代码不再适用的时候

template<typename T>
class Array {
private:
    T* data;
    ...
public:
    Array(Array<T> const&);
    Array<T>& operator= (Array<T> const&);
    void exchangeWith (Array<T>* b) {
        T* tmp = data;
        data = b->data;
        b->data = tmp;
    }
    T& operator[] (std::size_t k) {
        return data[k];
    }
    ...
};

template<typename T> inline
void exchange (T* a, T* b)
{
    T tmp(*a);
    *a = *b;
    *b = tmp;
}

透明自定义(Transparent Customization)

template<typename T>
void generic_algorithm(T* x, T* y)
{
    ...
    exchange(x, y); // How do we select the right algorithm?
    ...
}
template<typename T> inline
void quick_exchange(T* a, T* b) // (1)
{
    T tmp(*a);
    *a = *b;
    *b = tmp;
}

template<typename T> inline
void quick_exchange(Array<T>* a, Array<T>* b) // (2)
{
    a->exchange_with(b);
}

void demo(Array<int>* p1, Array<int>* p2)
{
    int x = 42, y = -7;
    quick_exchange(&x, &y); // uses (1)
    quick_exchange(p1, p2); // uses (2)
}

语义的透明性(Semantic Transparency)

struct S {
    int x;
} s1, s2;

void distinguish (Array<int> a1, Array<int> a2)
{
    int* p = &a1[0];
    int* q = &s1.x;
    a1[0] = s1.x = 1;
    a2[0] = s2.x = 2;
    quick_exchange(&a1, &a2); // *p == 1 after this (still)
    quick_exchange(&s1, &s2); // *q == 2 after this
}
int main()
{
    int* a = new int[3];
    a[0] = 1;
    int* p = &a[0]; // 之后a指向哪都不会改变p

    int* b = new int[3];
    int* tmp = b;
    b = a; // 此时abp都指向一处
    a = tmp; // a指向了原来b的那处,bp指向一处
    cout << a[0] << endl; // 一个未定义的数
    cout << b[0] << endl; // 1
    cout << *p << endl; // 1
}
// 更简单的例子
int main()
{
    int i = 1, j = 2;
    int* p = &i;
    int* q = p; // 之后p指向哪都不会改变q
    p = &j;
    cout << *q; // 1
}
template<typename T>
void exchange (Array<T>* a, Array<T>* b)
{
    T* p = &(*a)[0];
    T* q = &(*b)[0];
    for (std::size_t k = a->size(); k-- != 0; ) {
        exchange(p++, q++);
    }
}

重载函数模板

template<typename T>
int f(T)
{
    return 1;
}

template<typename T>
int f(T*)
{
    return 2;
}

int main()
{
    std::cout << f<int*>((int*)nullptr) << std::endl; // 1
    std::cout << f<int>((int*)nullptr) << std::endl; // 2
}

签名

template<typename T1, typename T2>
void f1(T1, T2);

template<typename T1, typename T2>
void f1(T2, T1);

template<typename T>
long f2(T);

template<typename T>
char f2(T);
#include <iostream>

template<typename T1, typename T2>
void f1(T1, T2)
{
    std::cout << "f1(T1, T2)\n";
}

template<typename T1, typename T2>
void f1(T2, T1)
{
    std::cout << "f1(T2, T1)\n";
}

int main()
{
    f1<char, char>('a', 'b'); // 二义性错误
}
// Translation unit 1:
#include <iostream>

template<typename T1, typename T2>
void f1(T1, T2)
{
    std::cout << "f1(T1, T2)\n";
}

void g()
{
    f1<char, char>('a', 'b');
}

// Translation unit 2:
#include <iostream>

template<typename T1, typename T2>
void f1(T2, T1)
{
    std::cout << "f1(T2, T1)\n";
}
extern void g(); // defined in translation unit 1

int main()
{
    f1<char, char>('a', 'b');
    g();
}

// output
f1(T2, T1)
f1(T1, T2)

重载的函数模板的局部排序

#include <iostream>

template<typename T>
int f(T)
{
    return 1;
}

template<typename T>
int f(T*)
{
    return 2;
}

int main()
{
    std::cout << f<int*>((int*)nullptr) << std::endl; // 1
    std::cout << f<int>((int*)nullptr) << std::endl; // 2
    // 下面的0被推断为int,匹配第一个模板
    // 第二个模板不是候选函数,重载解析在此未发生
    std::cout << f(0) << std::endl; //  calls f<T>(T)
    std::cout << f(nullptr); // calls f<T>(T)
    // 下面对两个模板的实参推断都可以成功,匹配程度一样
    // 但重载解析会选择产生自更特殊的第二个模板的函数
    // 因为第一个模板适用任何类型实参,第二个只适用指针类型实参
    std::cout << f((int*)nullptr); // calls f<T>(T*)
}

正式的排序原则

template<typename T>
void t(T*, T const* = nullptr, ...);

template<typename T>
void t(T const*, T*, T* = nullptr);

void example(int* p)
{
    t(p, p); // 错误:二义性调用
}

模板和非模板

#include <string>
#include <iostream>

template<typename T>
std::string f(T)
{
    return "Template";
}

std::string f(int&)
{
    return "Nontemplate";
}

int main()
{
    int x = 7;
    std::cout << f(x) << '\n'; // prints: Nontemplate
}
#include <string>
#include <iostream>

template<typename T>
std::string f(T&)
{
    return "Template";
}


std::string f(int const&)
{
    return "Nontemplate";
}

int main()
{
    int x = 7;
    std::cout << f(x) << '\n'; // prints: Template
    int const c = 7;
    std::cout << f(c) << '\n'; // prints: Nontemplate
}
template<typename T>
std::string f(T const&)
{
    return "Template";
}
#include <string>
#include <iostream>

class C {
public:
    C() = default;
    C (C const&) {
        std::cout << "copy constructor\n";
    }

    C (C&&) {
        std::cout << "move constructor\n";
    }

    template<typename T>
    C (T&&) {
        std::cout << "template constructor\n";
    }
};

int main()
{
    C x;
    C x2{x};             // prints: template constructor
    C x3{std::move(x)};  // prints: move constructor
    C const c;
    C x4{c};             // prints: copy constructor
    C x5{std::move(c)};  // prints: template constructor
}

可变参数函数模板

#include <iostream>

template<typename T>
int f(T*)
{
    return 1;
}

template<typename... Ts>
int f(Ts...)
{
    return 2;
}

template<typename... Ts>
int f(Ts*...)
{
    return 3;
}

int main()
{
    std::cout << f(0, 0.0); // calls f<>(Ts...)
    std::cout << f((int*)nullptr, (double*)nullptr); // calls f<>(Ts*...)
    std::cout << f((int*)nullptr); // calls f<>(T*)
}
#include <iostream>

template<typename... Ts> class Tuple
{
};

template<typename T>
int f(Tuple<T*>)
{
    return 1;
}

template<typename... Ts>
int f(Tuple<Ts...>)
{
    return 2;
}

template<typename... Ts>
int f(Tuple<Ts*...>)
{
    return 3;
}

int main()
{
    std::cout << f(Tuple<int, double>()); // calls f<>(Tuple<Ts...>)
    std::cout << f(Tuple<int*, double*>()); // calls f<>(Tuple<Ts*...>)
    std::cout << f(Tuple<int*>()); // calls f<>(Tuple<T*>)
}

显式特化

全局的类模板特化

template<typename T>
class S {
public:
    void info() {
        std::cout << "generic (S<T>::info())\n";
    }
};
template<>
class S<void> {
public:
    void msg() {
        std::cout << "fully specialized (S<void>::msg())\n";
    }
};
template<typename T>
class Types {
public:
    using I = int;
};

template<typename T, typename U = typename Types<T>::I>
class S; // (1)

template<>
class S<void> { // (2)
public:
    void f();
};

template<> class S<char, char>; // (3)

template<> class S<char, 0>; // ERROR: 0 cannot substitute U

int main()
{
    S<int>* pi; // OK: uses (1), no definition needed
    S<int> e1; // ERROR: uses (1), but no definition available
    S<void>* pv; // OK: uses (2)
    S<void, int> sv; // OK: uses (2), definition available
    S<void, char> e2; // ERROR: uses (1), but no definition available
    S<char, char> e3; // ERROR: uses (3), but no definition available
}

template<>
class S<char, char> { // definition for (3)
};
template<typename T>
class S;

template<> class S<char**> {
public:
    void print() const;
};

// 下面的定义不能使用template<>前缀
void S<char**>::print()
{
    std::cout << "pointer to pointer to char\n";
}
template<typename T>
class Outside {
public:
    template<typename U>
    class Inside {
    };
};
template<>
class Outside<void> {
    // 下面的嵌套类和上面定义的泛型模板之间并不存在联系
    template<typename U>
    class Inside {
    private:
        static int count;
    };
};

// 下面的定义不能使用template<>前缀
template<typename U>
int Outside<void>::Inside<U>::count = 1;
template <typename T>
class Invalid {
};

Invalid<double> x1; // 产生一个Invalid<double>实例化体

template<>
class Invalid<double>; // 错误:Invalid<double>已经被实例化了
// Translation unit 1:
template<typename T>
class Danger {
public:
    enum { max = 10; };
};

char buffer[Danger<void>::max]; // uses generic value

extern void clear(char*);

int main()
{
    clear(buffer);
}

// Translation unit 2:
template<typename T>
class Danger;

template<>
class Danger<void> {
public:
    enum { max = 100; };
};

void clear(char const* buf)
{
    // 可能与原先定义的数组大小不匹配
    for(int k=0; k < Danger<void>::max; ++k) {
        buf[k] = '\0';
    }
}

全局的函数模板特化

template<typename T>
int f(T) // (1)
{
    return 1;
}

template<typename T>
int f(T*) // (2)
{
    return 2;
}

template<> int f(int) // OK: specialization of (1)
{
    return 3;
}

template<> int f(int*) // OK: specialization of (2)
{
    return 4;
}
template<typename T>
int f(T, T x = 42)
{
    return x;
}

template<> int f(int, int = 35) // ERROR!
{
    return 0;
}

template<typename T>
int g(T, T x = 42)
{
    return x;
}

template<> int g(int, int y)
{
    return y/2;
}

int main()
{
    std::cout << f(0) << std::endl; // should print 21
}
#ifndef TEMPLATE_G_HPP
#define TEMPLATE_G_HPP

// 模板定义应放在头文件中
template<typename T>
int g(T, T x = 42)
{
    return x;
}

// 特化声明禁止模板进行实例化,但为避免重复不能在此定义
template<> int g(int, int y);
#endif // TEMPLATE_G_HPP

// 实现文件
#include "template_g.hpp"
template<> int g(int, int y)
{
    return y/2;
}

全局变量模板特化

template<typename T> constexpr std::size_t SZ = sizeof(T);
template<> constexpr std::size_t SZ<void> = 0;
template<typename T> typename T::iterator null_iterator;
template<> BitIterator null_iterator<std::bitset<100>>;
// BitIterator doesn't match T::iterator, and that is fine

全局成员特化

template<typename T>
class Outer { // (1)
public:
    template<typename U>
    class Inner { // (2)
    private:
        static int count; // (3)
    };
    static int code; // (4)
    void print() const { // (5)
        std::cout << "generic";
    }
};

template<typename T>
int Outer<T>::code = 6; // (6)

template<typename T> template<typename U>
int Outer<T>::Inner<U>::count = 7; // (7)

template<>
class Outer<bool> { // (8)
public:
    template<typename U>
    class Inner { // (9)
    private:
        static int count; // (10)
    };
    void print() const { // (11)
    }
};
template<>
int Outer<void>::code = 12;

template<>
void Outer<void>::print() const
{
    std::cout << "Outer<void>";
}
template<>
int Outer<void>::code;

template<>
void Outer<void>::print() const;
class DefaultInitOnly {
public:
    DefaultInitOnly() = default;
    DefaultInitOnly(DefaultInitOnly const&) = delete;
};

template<typename T>
class Statics {
private:
    static T sm;
};

// 下面只是一个声明
template<>
DefaultInitOnly Statics<DefaultInitOnly>::sm;
// 下面是定义(C++11前不存在定义的方法)
template<>
DefaultInitOnly Statics<DefaultInitOnly>::sm{};
template<>
    template<typename X>
    class Outer<wchar_t>::Inner {
    public:
        static long count; // 成员类型发生了改变
    };

template<>
    template<typename X>
    long Outer<wchar_t>::Inner<X>::count;
template<>
    template<>
    class Outer<char>::Inner<wchar_t> {
    public:
        enum { count = 1; };
    };

// 下列代码不合法:template<>不能位于模板实参列表后面
template<typename X>
template<> class Outer<X>::Inner<void>; // ERROR!
template<>
class Outer<bool>::Inner<wchar_t> {
public:
    enum { count = 2; };
};

局部的类模板特化

template<typename T>
class List { // (1)
public:
    ...
    void append(T const&);
    inline std::size_t length() const;
    ...
};
template<typename T>
class List<T*> { // (2)
private:
    List<void*> impl;
    ...
public:
    ...
    inline void append(T* p) {
    impl.append(p);
    }
    inline std::size_t length() const {
        return impl.length();
    }
    ...
};
template<>
class List<void*> { // (3)
    ...
    void append (void* p);
    inline size_t length() const;
    ...
};
template<typename T, int I = 3>
class S; // 基本模板

template<typename T>
class S<int, T>; // 错误:参数类型不匹配

template<typename T = int>
class S<T, 10>; // 错误:不能有默认实参

template<int I>
class S<int, I*2>; // 错误:不能有非类型表达式

template<typename U, int K>
class S<U, K>; // 错误:局部特化和基本模板没有本质区别

template<typename... Ts>
class Tuple;

template<typename Tail, typename... Ts>
class Tuple<Ts..., Tail>; // 错误:包扩展不在末尾

template<typename Tail, typename... Ts>
class Tuple<Tuple<Ts...>, Tail>; // OK:包扩展在嵌套模板实参列表末尾
template<typename C>
class List<void* C::*> { // (4)
public:
    // partial specialization for any pointer-to-void* member
    // every other pointer-to-member-pointer type will use this
    using ElementType = void* C::*;
    ...
    void append(ElementType pm);
    inline std::size_t length() const;
    ...
};
template<typename T, typename C>
class List<T* C::*> { // (5)
private:
    List<void* C::*> impl;
    ...
public:
    // partial specialization for any pointer-to-member-pointer type
    // except pointer-to-void* member which is handled earlier;
    // note that this partial specialization has two template parameters,
    // whereas the primary template only has one parameter
    using ElementType = T* C::*;
    ...
    void append(ElementType pm) {
        impl.append((void* C::*)pm);
    }
    inline std::size_t length() const {
        return impl.length();
    }
    ...
};
template<typename... Elements>
class Tuple; // primary template

template<typename T1>
class Tuple<T>; // one-element tuple

template<typename T1, typename T2, typename... Rest>

class Tuple<T1, T2, Rest...>; // tuple with two or more elements

局部的变量模板特化

template<typename T> constexpr std::size_t SZ = sizeof(T);

template<typename T> constexpr std::size_t SZ<T&> = sizeof(void*);
template<typename T> typename T::iterator null_iterator;

template<typename T, std::size_t N>
T* null_iterator<T[N]> = null_ptr;
// T* doesn't match T::iterator, and that is fine
上一篇下一篇

猜你喜欢

热点阅读