为什么函数模板不允许使用私有类型进行显式专业化?

Ser*_*nik 13 c++ language-lawyer

https://godbolt.org/z/s5Yh8e6b8

我不明白这背后的原因:为什么类模板允许显式专用化私有类型,但函数模板不允许?

假设我们有一堂课:

class pepe
{
    struct lolo
    {
        std::string name = "lolo";
    };
public:
    static lolo get()
    {
        return {};
    }
};
Run Code Online (Sandbox Code Playgroud)
  • 类模板可以显式特化。
  • 并且函数模板在隐式实例化时没有问题。
  • 尽管您无法创建,spec_class<pepe::lolo>{}因为pepe::lolo无法访问。
template <typename>
struct spec_class
{};

// this is ok
template <>
struct spec_class<pepe::lolo>
{};

// this will be ok also upon implicit instantiation
template <typename T>
void template_func(const T &t)
{
    std::cout << "implicit: " << t.name << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

但:

// this is not ok!
// template <>
// void template_func(const pepe::lolo &p)
// {
//     std::cout << "explicit: " << p.name << std::endl;
// }

// this is ok, but more or less understandable why
template <>
void template_func(const decltype(pepe::get()) &p)
{
    std::cout << "explicit: " << p.name << std::endl;
}

// not ok, but expected
// void func(const pepe::lolo&)
// {}
Run Code Online (Sandbox Code Playgroud)

那么: 为什么函数模板禁止显式专业化?

cig*_*ien 19

从 C++20 开始,由于PR0692,在函数模板的特化参数中使用私有成员是完全有效的。特别是,在temp.spec.general#6中添加了以下措辞:

通常的访问检查规则不适用于显式实例化或显式专业化声明中的名称,但出现在函数体、默认参数、基本子句成员规范枚举器列表或静态数据中的名称除外成员或变量模板初始值设定项。

[注 1:特别是,函数声明符中使用的模板参数和名称(包括参数类型、返回类型和异常规范)可以是通常无法访问的私有类型或对象。-尾注]

(强调我的)

代码未编译是由于GCC bug 97942造成的,并且它在 Clang 中编译得很好。演示