Table of contents
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.cpp
only reads func
the implementation of the function template and does not read any statements that need to generate function template instances, so it does not generate any func
function instances.
When compiling main.cpp
, although a function template instance is used, because main.cpp
only the func.hpp
header file is included, and the latter is just func
a declaration of a function template without a specific function implementation, the compiler cannot generate func
a 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 template
there 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 measureTherefore, 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++98
Provides another way to organize template code - Export Template
external 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 includeComeau 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
typename
andclass
, 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 mfp
the 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 typedef
alias for the defined pointer type. In this case, it some_class_mfp
is 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_by
is some_class_mfp
an alias, which some_class_mfp
is 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_same
Used 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;
};
typename
The function is to explicitly call to prompt the compiler to "execute" the meta-function, otherwise the logic will be incorrect.