模板类中的模板成员专用化

  • 本文关键字:专用 成员 c++ templates
  • 更新时间 :
  • 英文 :

#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 编译。那么哪一个是对的呢?

但我真正的问题是,假设叮当做对了,为什么这又不起作用:

#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

    一个成员函数,
  1. 一个成员函数模板,一个成员类,一个 成员枚举、成员类模板、静态数据成员或 类模板的静态数据成员模板可以是显式的 专用于隐式的类专用化 实例;在这种情况下,类模板的定义应 在类成员的显式专用化之前 模板。如果对类的成员进行这种明确的专用化 模板名称隐式声明的特殊成员函数 (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
}

根据:

  1. 在类成员的显式专用化声明中 模板或命名空间范围中显示的成员模板, 成员模板及其某些封闭类模板可能会保留 非专业,但声明不得明确 专用化类成员模板(如果其封闭类模板( 也没有明确的专业化。

并且因为:

  1. 函数模板、类模板或变量的声明 明确专门的模板应在声明之前 明确的专业化。

因此,这不应该在外部模板声明中:

template <typename U>
struct A {
template<typename...Ts> auto func();
template<> auto func<int>() { return std::string{"foo"}; } // should not work
};

我不知道为什么叮当允许这样做。

但它允许位于声明主模板的命名空间作用域中,在本例中为全局命名空间作用域。

最新更新