成员功能模板专业化是否可以具有与主模板不同的访问级别

May a member function template specialization have a different access level than the main template?

本文关键字:访问级别 专业化 功能 是否 成员      更新时间:2023-10-16

我在回答一个关于删除函数的问题时提到,成员函数模板不能在类范围内专门化。这让我怀疑成员函数模板专业化是否有可能拥有与主模板不同的访问级别。在下面的代码中,我试图拥有一个公共成员函数模板的私有专业化:

#include <iostream>
class Foo {
public:
template<typename T>
void func(T) { std::cout << "Publicn"; }
private:
template<>
void func<char>(char) { std::cout << "Privaten"; }
friend int main();
};
int main()
{
Foo f;
f.func(10);
f.func('a');
}

使用最新的MSVC,它编译、运行并产生预期的输出:

Public
Private

对于g++4.8和Clang 3.2,该代码被拒绝。Clang这样说:

error: explicit specialization of 'func' in class scope
void func<char>(char) { std::cout << "Privaten"; }
^

假设g++和Clang使用C++11的14.7.3/2作为他们行为的基础,但我认为可能有一点回旋余地,因为3.3.6/3说全局范围是一个命名空间,全局命名空间(间接)包含了模板专用化。

我的问题不是关于标准的这些部分,也不是关于这些编译器的任何行为,而是关于成员函数模板是否可能具有与通用模板不同的访问级别的专门化。例如,是否可以有一个公共成员函数模板和该模板的私有专用化?

我们总是可以手动完成。

一些随机的SFINAE机器:

#include <iostream>
#include <utility>
#include <type_traits>
template<typename T> constexpr bool IsInt() { return std::is_same<T,int>::value; }
template<std::size_t>
struct SecretEnum {
enum class hidden {};
};
template<bool b, int i=1> using EnableIf = typename std::enable_if<b,typename SecretEnum<i>::hidden>::type;
class Foo {
public:
template<typename T, EnableIf< !IsInt<T>(), 1 >...>
void func(T) { std::cout << "Publicn"; }
private:
template<typename T, EnableIf< IsInt<T>(), 2 >...>
void func(T) { std::cout << "Private with intn"; }
friend int main();
};
int main()
{
Foo f;
f.func(10);
f.func('a');
}

现在这个技巧不适用于clang,因为我上次检查时是如何进行SFINAE和方法区分的。但这可以用其他类似的技巧来代替(比如第二个参数中基于指针的默认参数——用EnableIf< IsInt<T>(), 2 >* = nullptr或类似的clang来代替EnableIf< IsInt<T>(), 2 >...。我只是觉得它不那么吸引人。)

那么,上面发生了什么?我有两个不同的func过载。两者都是模板函数,其中一个参数是T,还有一个秘密枚举包,其类型在T分别与IsInt<T>()!IsInt<T>()测试匹配时和仅当CCD_5匹配时有效。在这两种情况下,包的类型不同(一种是SecretEnum<2>::hidden,另一种是CCD _9),因此它们的签名差异很大,足以满足大多数C++11编译器的要求(clang认为它们在上次检查时是相同的,产生了错误,我认为clang错了)。

当您调用func<blah>时,它会检查两个func中的哪一个(如果有的话)是合适的。由于它们的条件是完全相反的,所以只有其中一个是合适的。

实际上,我们正在进行手工专业化。

在C++1y中,如果恒星正确对齐,并且技术报告中的概念lite允许这样做,我们可能能够template<IsInt T>template<IsNotInt T>