C++ Templates

【C++ Templates(13)】实例化

2018-05-17  本文已影响49人  downdemo

On-Demand实例化(隐式实例化/自动实例化)

template<typename T> class C; // (1) 前置声明

C<int>* p = 0; // (2) 正确:不需要C<int>的定义

template<typename T>
class C {
public:
    void f(); // (3) 成员声明
}; // (4) 类模板定义结束

void g (C<int>& c) // (5) 只使用类模板声明
{
    c.f(); // (6) 使用了类模板定义,需要C::f()的定义
}

template<typename T>
void C<T>::f() // (6)需要的定义
{
}
C<void>* p = new C<void>;
template<typename T>
class C {
public:
    C(int);
};

void candidate(C<double>);
void candidate(int) {}

int main()
{
    candidate(42); // 前两个函数声明都可以被调用
}

延迟实例化

template <typename T>
class Safe {
};

template <int N>
class Danger {
    int arr[N]; // N<=0则失败
    // 但编译器会假设最好的结果,即N是正整数
};

template <typename T, int N>
class Tricky {
public:
    void noBodyHere(Safe<T> = 3); // 不一定能用整数对模板Safe初始化
    // 但编译器会假设对Safe<T>的泛型定义不会用到这个默认实参
    void inclass() {
        Danger<N> noBoomYet; // OK until inclass() is used with N<=0
    }
    void error() { // 会引发错误
        Danger<-1> boom;
    }
    // Danger<-1>会被要求给出类Danger<-1>的完整定义
    // 于是会定义一个-1大小的数组
    // 即使error没被使用不被实例化,也仍会引发错误
    void unsafe(T (*p)[N]); // 在N没被模板参数替换前该声明不会出错
    T operator->();
    // virtual Safe<T> suspect();
    struct Nested {
        Danger<N> pfew; // OK until Nested is used with N<=0
    };
    union { // 匿名union
        int align;
        Safe<T> anonymous;
    };
};

int main()
{
    Tricky<int, 0> ok; // 默认构造函数和析构函数肯定会被调用
    // 因此它们的定义必须存在,虚函数的定义也必须存在
    // 因此suspect()只有声明没有定义则会出现链接错误

    // 对于inclass()和结构Nested的定义,会要求一个Danger<0>类型
    // 但因为没有用到这两个成员的定义,因此不会产生定义而引发错误

    // 所有成员声明都会被生成,因此N为0时unsafe(T (*p)[N])会产生错误
    // 同理,如果匿名union中的不是Safe<T>而是Danger<T>也会产生错误

    // 对于operator->通常应该返回指针类型,或用于这个操作符的class类型
    // 但在模板中规则会更灵活,虽然这里T为int,返回int类型,但不会出错
}

C++的实例化模型

两阶段查找

POI

class MyInt {
public:
    MyInt(int i);
};

MyInt operator - (MyInt const&);

bool operator > (MyInt const&, MyInt const&);
using Int = MyInt;

template<typename T>
void f(T i)
{
    if (i>0) {
        g(-i);
    }
}
// (1)
void g(Int)
{
    // (2)
    f<Int>(42); // 调用点
    // (3)
}
// (4)
template<typename T>
class S {
public:
    T m;
};
// (5)
unsigned long h()
{
    // (6)
    return (unsigned long)sizeof(S<int>);
    // (7)
}
// (8)
template<typename T>
class S {
public:
    using I = int;
};

// (1)
template<typename T>
void f()
{
    S<char>::I var1 = 41;
    typename S<T>::I var2 = 42;
}

int main()
{
    f<double>();
}
// (2): (2a), (2b)

包含模型与分离模型

// Translation unit 1:
#include <iostream>
export template<typename T>
T const& max (T const&, T const&);

int main()
{
    std::cout << max(7, 42) << std::endl; // (1)
}

// Translation unit 2:
export template<typename T>
T const& max (T const& a, T const& b)
{
    return a < b ? b : a; // (2)
}

跨翻译单元查找

// Translation unit 1:
#include <iostream>
export template<typename T>
T const& max(T const&, T const&);

namespace N {
    class I {
    public:
        I(int i): v(i) {}
        int v;
    };
    bool operator < (I const& a, I const& b) {
        return a.v < b.v;
    }
}

int main()
{
    std::cout << max(N::I(7), N::I(42)).v << std::endl; // (3)
}

例子

template<typename T>
void f1(T x)
{
    g1(x); // (1)
}

void g1(int)
{
}

int main()
{
    f1(7); // ERROR: g1 not found!
} // (2) POI for f1<int>(int)
// File common.hpp:
export template<typename T>
void f(T);

class A {
};
class B {
};

class X {
public:
    operator A() { return A(); }
    operator B() { return B(); }
};

// File a.cpp:
#include "common.hpp"

void g(A)
{
}

int main()
{
    f<X>(X());
}

// File b.cpp:
#include "common.hpp"

void g(B)
{
}

export template<typename T>
void f(T x)
{
    g(x);
}

显式实例化

template<typename T>
void f(T)
{
}

// 4个有效的显式实例化体
template void f<int>(int);
template void f<>(float);
template void f(long);
template void f(char);
template<typename T>
class S {
public:
    void f() {
    }
};
template void S<int>::f();
template class S<void>;
// File toast.hpp:
template<typename T>
void toast(T const& x)
{
    ...
}

// Client code:
#include "toast.hpp"
template void toast(float);

手动实例化(Manual Instantiation)

// Translation unit 1:
template<typename T>
void f(); // 没有定义,禁止在这个编译单元实例化

void g()
{
    f<int>();
}

// Translation unit 2:
template<typename T>
void f()
{
}

template void f<int>(); // 手动实例化

void g();

int main()
{
    g();
}
// f.hpp:
template<typename T>
void f(); // no definition: prevents instantiation

// t.hpp:
#include "f.hpp"
template<typename T>
void f()
{
}

// f.cpp:
#include "f.tpp"

template void f<int>(); // 手动实例化

显式实例化声明(Explicit Instantiation Declarations)

// t.hpp:
template<typename T> void f()
{
}

extern template void f<int>();    // declared but not defined
extern template void f<float>();  // declared but not defined

// t.cpp:
template void f<int>();           // definition
template void f<float>();         // definition

编译期if语句

template<typename T> bool f(T p) {
    if constexpr (sizeof(T) <= sizeof(long long)) {
        return p > 0;
    } else {
        return p.compare(0) > 0;
    }
}
bool g(int n) {
    return f(n);  // OK
}
template<bool b>
struct Dispatch { // only to be instantiated when b is false
    static bool f(T p) { // (due to next specialization for true)
        return p.compare(0) > 0;
    }
};

template<>
struct Dispatch<true> {
    static bool f(T p) {
        return p > 0;
    }
};

template<typename T> bool f(T p) {
    return Dispatch<sizeof(T) <= sizeof(long long)>::f(p);
}

bool g(int n) {
    return f(n); // OK
}
template<typename Head, typename... Remainder>
void f(Head&& h, Remainder&&... r) {
    doSomething(std::forward<Head>(h));
    if constexpr (sizeof...(r) != 0) {
        // handle the remainder recursively (perfectly forwarding the arguments):
        f(std::forward<Remainder>(r)...);
    }
}
void h();
void g() {
    if constexpr (sizeof(int) == 1) {
        h();
    }
}

In the Standard Library

namespace std {
    template<typename charT, typename traits = char_traits<charT>,
        typename Allocator = allocator<charT>>
    class basic_string {
        ...
    };
    extern template class basic_string<char>;
    extern template class basic_string<wchar_t>;
}
上一篇 下一篇

猜你喜欢

热点阅读