为何友元函数允许显式特化,而类内普通函数模板的显式特化却被禁止?
为何友元函数允许显式特化,而类内普通函数模板的显式特化却被禁止?
先给你说个C++里的通用规则:显式特化只能在命名空间作用域(或者全局作用域)进行,类作用域里是不允许的。咱们看个直观的例子就懂了:
比如这段代码,在类模板里尝试对普通成员函数模板做显式特化:
template<typename T> class B { template<typename U> void test(T) {}; template<> void test(int) {}; // 试图在这里特化U为int };
用g++编译的话,直接就会抛错:
error: explicit specialization in non-namespace scope
这就是因为我们违反了刚才说的规则——在类作用域里直接搞函数模板的显式特化,编译器根本不认。
但有意思的是,友元函数模板的特化却是个例外,甚至这还是让类模板里的友元函数模板正常工作的两种可行方法之一。比如下面这段代码就能完美编译运行:
template<typename T> class B; template<typename T> void test(B<T>); template<typename T> class B { friend void test<>(B<T>); // 这里是对友元模板的显式特化 };
不过别误会,这不是说类作用域里就能随便搞友元特化了——如果咱们尝试在类作用域内直接定义并特化友元模板,照样会和上面的例子报一样的错:
template<typename T> class B { template<typename U> friend void test(B<T>); // 试图在类内直接特化这个友元模板 template<> friend void test<int>(B<T>); };
这时候编译器还是会抛出:error: explicit specialization in non-namespace scope
那为什么会有这种区别?核心原因很简单:
- 类内的普通成员函数模板特化:是直接在类作用域内创建了一个新的特化版本,这完全违反了C++标准对显式特化作用域的要求,所以必然报错。
- 友元函数模板的合法特化:你在类里写的
friend void test<>(B<T>);,本质上是引用了一个已经在命名空间/全局作用域声明的模板特化,只是在类里给这个外部的特化开了友元权限而已——并没有在类作用域内创建新的特化,自然符合规则。
备注:内容来源于stack exchange,提问作者tntnkn
相关产品推荐
相关产品推荐

