成员函数模板专业化可能具有与主模板不同的访问级别吗?

Kno*_*abe 8 c++ templates c++11

关于删除函数的问题的答案提到了成员函数模板如何不能在类范围内专门化.这让我想知道成员函数模板专业化是否可能具有与主模板不同的访问级别.在下面的代码中,我正在尝试使用公共成员函数模板的私有特化:

#include <iostream>

class Foo {
public:
  template<typename T>
  void func(T) { std::cout << "Public\n"; }

private:
  template<>
  void func<char>(char) { std::cout << "Private\n"; }

  friend int main();
};

int main()
{
  Foo f;
  f.func(10);
  f.func('a');
}
Run Code Online (Sandbox Code Playgroud)

使用最新的MSVC,它可以编译,运行并生成预期的输出:

Public
Private
Run Code Online (Sandbox Code Playgroud)

使用g ++ 4.8和Clang 3.2,代码被拒绝.Clang说:

error: explicit specialization of 'func' in class scope
void func<char>(char) { std::cout << "Private\n"; }
     ^
Run Code Online (Sandbox Code Playgroud)

据推测,g ++和Clang使用14.7.3/2的C++ 11作为他们行为的基础,但我认为可能会有一点摆动空间,因为3.3.6/3表示全局范围是命名空间,并且全局命名空间(间接)包含模板特化.

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

Yak*_*ont 2

我们总是可以手动完成。

一些随机的 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 << "Public\n"; }

private:
  template<typename T, EnableIf< IsInt<T>(), 2 >...>
  void func(T) { std::cout << "Private with int\n"; }

  friend int main();
};

int main()
{
  Foo f;
  f.func(10);
  f.func('a');
}
Run Code Online (Sandbox Code Playgroud)

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

那么上面是怎么回事呢?我有两个不同的重载func。两者都是模板函数,其中一个参数是 a T,以及一组秘密枚举,当且仅当分别与或testT匹配时,其类型才有效。包的类型在两种情况下有所不同(一种是,另一种是),因此它们的签名足够不同,足以满足大多数 C++11 编译器的要求(clang 认为它们在我上次检查时是相同的,产生错误,我相信 clang 是错误的)。IsInt<T>()!IsInt<T>()SecretEnum<2>::hiddenSecretEnum<1>::hidden

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

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

在 C++1y 中,如果星星正确对齐并且技术报告中的概念精简版可以实现这一点,我们也许能够做到这template<IsInt T>一点。template<IsNotInt T>