c++ - 模板类中的模板成员特化
问题描述
#include <iostream>
#include <string>
template<typename U>
struct A
{
template<typename... Ts> auto func();
template<> auto func<int>();
};
template<typename U>
template<>
auto
A<U>::func<int>() { return std::string{"foo"}; }
int main()
{
A<float> a{};
std::cout << a.func<int>() << std::endl;
}
这不起作用,因为模板类的模板成员的专门化是不可能的,除非您也专门化该类。(我读到过。)
但是如果将成员特化的定义移到类定义中,它确实有效:
#include <iostream>
#include <string>
template<typename U>
struct A
{
template<typename... Ts> auto func();
template<> auto func<int>() { return std::string{"foo"}; }
};
int main()
{
A<float> a{};
std::cout << a.func<int>() << std::endl;
}
我不确定我是否完全理解为什么。此外,当它使用 clang 时,它不能使用 gcc 编译。那么哪一个是对的呢?
但我真正的问题是,假设 clang 是正确的,为什么这又不起作用:
#include <iostream>
#include <string>
template<typename U>
struct A
{
template<typename... Ts> auto func();
template<> auto func<U>() { return std::string{"foo"}; }
};
int main()
{
A<int> a{};
std::cout << a.func<int>() << std::endl;
}
这是一个不同的错误,不是非特化模板成员的特化,而是抱怨是func<int>
在定义之前不能使用推导的返回类型。
解决方案
如果我们看n4810 § 13.8.3
- 成员函数、成员函数模板、成员类、成员枚举、成员类模板、静态数据成员或类模板的静态数据成员模板可以显式特化为隐式实例化的类特化;在这种情况下,类模板的定义应在类模板成员的显式特化之前。如果类模板成员的这种显式特化命名了一个隐式声明的特殊成员函数(11.3.3),则程序格式错误。
但是,您可以这样做,其中两者都是专门的:
template<typename U>
struct A
{
template<typename... Ts> auto func() { /* ... */ }
};
template <>
template <>
auto A<int>::func<int>()
{
// ok, enclosing class template explicitly specialized
}
虽然这是无效的 C++:
template <typename U>
template <>
auto A<U>::func<int>()
{
// ops: invalid, enclosing class template not explicitly specialized
}
根据:
- 在类模板的成员或出现在命名空间范围内的成员模板的显式特化声明中,成员模板和它的一些封闭类模板可能保持未特化,除非声明不应显式特化类成员模板,如果它封闭类模板也没有明确专门化。
因为:
- 显式特化的函数模板、类模板或变量模板的声明应在显式特化的声明之前。
因此这不应该在外部模板声明中:
template <typename U>
struct A {
template<typename...Ts> auto func();
template<> auto func<int>() { return std::string{"foo"}; } // should not work
};
我不知道为什么clang允许这样做。
但它允许在声明主模板的命名空间范围内,在本例中为全局命名空间范围。
推荐阅读
- r - 如何在r中找到三维数据的轮廓线的外部界限
- javascript - 使用 Angular 指令在模板中绘制对象
- python - 如何在 SQLAlchemy 的原始 JOIN 查询中正确选择重复的字段名称
- machine-learning - 特征提取、选择和分类概念
- c - fgets - 数组大小和 int num 之间的差异
- bash - bash - 将可选参数传递给脚本 - 参数名 + 字符串值
- java - 在整数索引 POI Java 中翻译字母(字符)索引
- android - HTTP 请求查询:我可以通过 HTTP 请求发送视频吗?并发送回 json 数据和图像?
- c# - ManagementBaseObject 和 ManagementObject 给出不同的 DeviceId
- powershell - 需要匹配2个CSV文件中的字段,然后根据一个字段的内容,返回另一个字段