Advanced skills in C++ template programming

How are function modules linked?

In the following files

// func.hpp
template<typename T>
T const& func(T const &v);
// func.cpp
template<typename T>
T const& func(T const &v)
{
    
    
    return v;
}

When compiled it will produceerror

undefined reference to `int const& func<int>(int const&)'

When compiling, the compiler func.cpponly reads functhe implementation of the function template and does not read any statements that need to generate function template instances, so it does not generate any funcfunction instances.

When compiling main.cpp, although a function template instance is used, because main.cpponly the func.hppheader file is included, and the latter is just funca declaration of a function template without a specific function implementation, the compiler cannot generate funca function module instance at this time, so it has to keep it. A call link, expecting the function implementation to be found during the final link process, but the implementation does not exist, so the link fails

At this point you can use explicitly generated function templates

// func.cpp
template<typename T>
T const& func(T const &v)
{
    
    
    return v;
}

template int const& func(int const &v); // 明确生成模板实例 指示编译器根据此函数声明寻找合适的模板实现

When templatethere is no template parameter list after the keyword, but a function declaration, it means that the compiler is instructed to find a suitable template implementation based on this function declaration.

At this point the function is declared as T=int, but this is only a stopgap measure

Therefore, the implementation of the template should also be placed in the header file. At this time, the implementation of the template can be directly included in other code files. When a template instance needs to be generated, the compiler can generate it on the spot based on the known template implementation, eliminating the need for Depend on template instances generated in other target files

Export Template

C++98Provides another way to organize template code - Export Templateexternal name template (templates that place definition and implementation in the same header file can be called internal name templates)

// func.hpp
export template<typename T>
T const& func(T const &v);
// func.cpp
export template<typename T>
T const& func(T const &v)
{
    
    
    return v;
}

Currently publicly announced C++compilers that support foreign name templates include Comeau C++andBorland C++

Some uses of class templates

Pre-class template generation

template<typename T> class my_class; // 前置类模板生成

Member function template implemented within class template

template<typename T=int>
class my_class
{
    
    
    // 在类模板内实现的成员函数模板
    void push(T const &v)
    {
    
    
        std::cout << "push" << std::endl;
    }
}

Member function declaration, which will be implemented outside the class template

template<typename T=int>
class my_class
{
    
    
	// 成员函数声明,将在类模板外实现
    void pop();
};

Member function template implemented outside class template

template<typename T>
void my_class<T>::pop()
{
    
    
	std::cout << "pop" << std::endl;
}

Member function template: The member function template of an ordinary class can be implemented on the spot in the class or separately outside the class.

struct normal_class
{
    
    
	template<typename T>
    void set(T const &v) {
    
    value = int(v);}
    template<typename T>
    T get();
};

template<typename T>
T normal_class::get()
{
    
    
	return T(value);
}

Member functions of class templates can also have additional template parameters

template<typename T0>
struct normal_class
{
    
    
    template<typename T1>
    T1 get();
};
template<typename T0> template<typename T1>
T1 normal_class<T0>::get()
{
    
    
    return T1(value);
}

Template parameter type

Generally, template parameters are marked with typenameand class, and in the implementation of function and class templates, template parameters are used to refer to specific types. Therefore, the template parameters of the type marked with these two keywords are called type template parameters. , in addition to the following four types

  • Integers and enumerations
  • pointer to object or function
  • Reference to object function
  • pointer to object member

The above four parameters are collectively called non-type template parameters. Their declaration method in the template parameter list is consistent with the variable declaration of the corresponding type. In addition, the template parameter can also be a template, which is called a template template parameter.

The role of non-type template parameters is equivalent to predefining some constants for function templates or class templates. When generating template instances, it is also required that constants, that is, values ​​known at compile time, must be assigned to non-type template parameters.

integer template parameters

When different variables need to be defined for the same algorithm or class, it is most suitable to use non-type template parameters. This can not only avoid rewriting the code due to different constants, but also avoid the inconvenience caused by implementing known constants as variables. additional operating overhead

template<typename T, unsigned size>
class ay
{
    
    
    T elems[size];
public:
    T& operator[](unsigned i)
    {
    
    
        return elems[i];
    }
};
    ay<char, 2> ap{
    
    }; // 调用

pointer to object or function

To achieve the optimal implementation between change and immutability, usually the function pointer is used as a callbackcallback

template<typename T, void (*f)(T &v)>
void foreach(T array[], unsigned size)
{
    
    
    for (unsigned i = 0; i < size; i ++)
    {
    
    
        f(array[i]);
    }
}

template<typename T>
void inc(T &v)
{
    
    
    ++ v;
}
template<typename T>
void dec(T &v)
{
    
    
    -- v;
}
template<typename T>
void print(T &v)
{
    
    
    std::cout << v << ' ';
}
    int arr[] = {
    
    
            1, 2, 3, 4, 5
    };
    foreach<int, print<int>> (arr, 5);
    foreach<int, inc<int>> (arr, 5);
    foreach<int, print<int>> (arr, 5);

Pointer and reference template parameters

slightly

Member function pointer template parameters

When a member function pointer is used as a template parameter, its usage is similar to that of a function pointer template parameter.

int (some_class::* mfp)(int);

class some_value
{
    
    
private:
    int value;
public:
    explicit some_value(int _value): value(_value){
    
    }
    int add_by(int op){
    
    
        return value += op;
    }
    int sub_by(int op){
    
    
        return value -= op;
    }
};

Except for mfpthe exception, other parts are used to describe the details of the pointed function. When you need to define member function pointers of the same type in multiple places, you can first use an typedefalias for the defined pointer type. In this case, it some_class_mfpis an alias.

typedef int (some_class:: *some_class_mfp)(int);

some_class_mfp mfp;
template<some_value_mfp func>
int call(some_value &va, int op)
{
    
    
    return (va.*func)(op);
}

This &some_value::add_byis some_class_mfpan alias, which some_class_mfpis a type, similar to a pointer to an object or function.

    some_value v0(0);
    cout << call<&some_value::add_by>(v0, 1) << endl;

Metaprogramming Tips

Providing reusable code support for various basic types of operations is C++an important topic of metaprogramming

The most basic requirement in type operations is to deduce another type based on several types (for example, given a container type, get its iterator type; or given an iterator type, find its label type)

C++A mechanism that can derive other compile-time known elements from several compile-time known elements can be called a meta-function .

The template is the body of the meta-function, the template parameters are the parameters of the meta-function, and the nested definition in the template is the return value of the meta-function. When there are special cases when modifying the template, it is equivalent to implementing a conditional judgment logic in the meta-function.

#if 模板实参匹配模板特例参数
	@echo 特例中的类型
#else if 
	@echo 通例中的类型

customary

template<typename T0, typename T1>
struct is_same
{
    
    
    enum {
    
    
        result = 0
    };
};

template<bool cond, typename Type_True, typename Type_false>
struct if_
{
    
    
    typedef Type_True return_type;
};

special case

template<typename T>
struct is_same<T, T>
{
    
    
    enum {
    
    
        result = 1
    };
};

template<typename Type_True, typename Type_false>
struct if_<false, Type_True, Type_false>
{
    
    
    typedef Type_True return_type;
};

is_sameUsed to determine whether two types are the same. Since its return value needs to have Boolean semantics, the meta-function if_implementation returns one of the two types based on conditions.

template<typename MV1, typename MV2, typename tag1, typename tag2>
struct return_type_of
{
    
    
    typedef typename if_<is_same<tag1, matrix_tag>::result && is_same<tag2, vector_tag>::result,
                        MV2, MV2>::return_type return_type;
};

typenameThe function is to explicitly call to prompt the compiler to "execute" the meta-function, otherwise the logic will be incorrect.

Guess you like

Origin blog.csdn.net/qq_48322523/article/details/128758684