为什么函数模板不允许使用私有类型的显式特化?
Why isn't explicit specialization with private type allowed for function templates?
https://godbolt.org/z/s5Yh8e6b8
我不明白这背后的原因:为什么 class 模板允许私有类型的显式特化而不是函数模板?
假设我们有一个 class:
class pepe
{
struct lolo
{
std::string name = "lolo";
};
public:
static lolo get()
{
return {};
}
};
- Class 模板可以明确特化。
- 并且函数模板在隐式实例化时没有问题。
- 尽管您无法创建
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;
}
但是:
// 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&)
// {}
所以:
为什么函数模板禁止显式特化?
从 C++20 开始,在函数模板特化的参数中使用私有成员是完全有效的,因为 PR0692. In particular, the following wording was added to temp.spec.general#6:
The usual access checking rules do not apply to names in a declaration of an explicit instantiation or explicit specialization, with the exception of names appearing in a function body, default argument, base-clause, member-specification, enumerator-list, or static data member or variable template initializer.
[ Note 1: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) can be private types or objects that would normally not be accessible. - end note]
(强调我的)
代码未编译是由于 GCC bug 97942, and it compiles just fine in Clang. demo。
https://godbolt.org/z/s5Yh8e6b8
我不明白这背后的原因:为什么 class 模板允许私有类型的显式特化而不是函数模板?
假设我们有一个 class:
class pepe
{
struct lolo
{
std::string name = "lolo";
};
public:
static lolo get()
{
return {};
}
};
- Class 模板可以明确特化。
- 并且函数模板在隐式实例化时没有问题。
- 尽管您无法创建
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;
}
但是:
// 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&)
// {}
所以: 为什么函数模板禁止显式特化?
从 C++20 开始,在函数模板特化的参数中使用私有成员是完全有效的,因为 PR0692. In particular, the following wording was added to temp.spec.general#6:
The usual access checking rules do not apply to names in a declaration of an explicit instantiation or explicit specialization, with the exception of names appearing in a function body, default argument, base-clause, member-specification, enumerator-list, or static data member or variable template initializer.
[ Note 1: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) can be private types or objects that would normally not be accessible. - end note]
(强调我的)
代码未编译是由于 GCC bug 97942, and it compiles just fine in Clang. demo。