重载模板函数时显式专用化和常规函数之间的区别
Difference between explicit specialization and regular functions when overloading a template function
我今天在滚动。这是n00b问题7:
当您尝试重载模板函数时,显式专用化和仅常规函数之间有什么区别?
使用显式专业化的适当情况是什么?我不太明白:
#include <iostream>
template <typename s> void test(s var1);
template <> void test<int>(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
template <> void test<int>(int var1){
std::cout << "int " << var1 << std::endl;
}
反对:
#include <iostream>
template <typename s> void test(s var1);
void test(int var1);
int main(){
test(1);
test(1.1);
test("hello!!");
return 0;
}
template <typename s> void test(s var1){
std::cout << var1 << std::endl;
}
void test(int var1){
std::cout << "int " << var1 << std::endl;
}
显式专用模板函数和非模板常规函数之间实际上没有区别,除了当编译器为函数调用查找匹配的签名类型时,它将首先选择一个与所需签名匹配的非模板函数,然后再尝试实例化任何可能满足所需签名匹配的可用模板函数。
如果要在不是模板函数的头文件中声明和定义一个函数,则必须将该函数声明为 inline
。 这是因为模板函数在实际实例化之前不是与代码模块链接的实际函数。然后,链接器在编译代码模块后丢弃该实例化。 如果链接器没有这样做,则每次.cpp文件包含头文件时,链接器都会抱怨函数的定义重复。 在非模板函数上使用 inline
关键字在编译器级别具有类似的效果,因为每当在 .cpp 文件中使用该函数时,编译器都会将该函数调用替换为头文件中inline
函数的函数代码主体,并避免函数调用与关联的堆栈活动记录设置和清理的开销。 因此,链接器不会抱怨函数的重复定义。
我不是专家,但我的经验是在我想定义不同的返回类型时使用模板(和专业化)。 不能重载函数的返回类型。
一个主要的区别是: 显式专用化根本不参与重载。
template<typename T> void f(T const&);
template<> void f<char const*>(char const * const&);
与f("hello")
通话不会考虑任何明确的专业化。它只会采用所有模板,并推断出它们的模板参数。以上T
将被推导出为char[6]
,因此不会选择专业。
如果改为重载函数模板,则具有完全不同的特征。
template<typename T> void f(T const&);
void f(char const * const&);
调用这个函数,它将选择第二个函数,因为生成的专用化的(char const(&)[6])
参数和(char const * const&)
参数都同样匹配参数,但第二个函数是非模板函数,因此最终首选它。
当编译器遇到函数调用时,它首先查找非模板函数定义,然后查找显式专用模板,最后查找签名与函数调用匹配的模板定义。因此,例如,如果您有一个显式定义的模板和一个模板,则编译器会选择显式定义的模板。因此,当您希望以与模板处理特定数据类型的方式不同的方式处理特定数据类型时,应使用显式专用模板。
显式专用化的另一个用途是当您想要"重载"不接受任何参数的函数时。您可以使用显式专用化为函数提供不同的定义,以处理不同的数据类型。
我直言,当您要使用显式模板参数调用该函数时,应该使用function template
的显式专用化。
test<int>(myClass); // no argument for 'int' -> declare test() as template specialization
在其他情况下,您应该始终使用正常的专业化。
test(10, myClass); // argument 10 is 'int' -> test() should be normal specialized
从技术上讲,函数的正常模板专用化和显式模板专用化之间没有区别。普通的专用版本完全独立于template
功能。
- 是否可以使用单个定义定义函数的常量和常规版本?(使用模板,自动,decltype等)
- G++ 编译器是否在未使用返回值的情况下将 constexpr 函数视为常规函数?
- C++常规指针函数或模板
- 在C++中,为什么使用静态类函数而不是常规函数?
- 模板与常规函数歧义 - UB?
- 如何使用模板生成常规参数列表并将其传递给运行时函数?
- 为什么非放置"新建"和"删除"内置于语言中,而不仅仅是常规函数?
- 是否有任何常规方法可以通知 STL 移动和复制构造函数?
- 使常规函数使用模板包装成员函数
- 如何初始化堆,以便静态构造函数可以在常规 MFC dll 中使用堆?
- Arduino "delay"函数的常规c ++等价物是什么?
- 为什么C++列表初始化也考虑常规构造函数?
- 编译器如何以不同于常规函数的方式处理 lambda?
- 函数模板和常规重载
- C++中的错误处理,构造函数与常规方法
- 函数指针和常规调用的区别
- 使用 boost::this_thread::sleep_for() 和常规睡眠() 函数有什么区别
- 为什么我的函数不跳过尝试解析为不兼容的模板函数,而默认解析为常规函数?
- 指向多值函数的常规指针
- 为什么使用虚函数而不是常规函数