【问题标题】:Template member specialization in template class模板类中的模板成员特化
【发布时间】:2019-08-16 20:19:06
【问题描述】:
#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&lt;int&gt;

【问题讨论】:

  • 这些都不应该编译。模板特化只允许在命名空间范围内声明。
  • @Brian 当你说命名空间范围内允许模板特化时,你能详细说明一下吗
  • @Kapil 您希望我详细说明其中的哪一部分?
  • 即使我在某个命名空间中添加了这个模板声明,我也会得到同样的错误,所以当你说模板专业化只允许在命名空间范围内是什么意思
  • 这段代码在 clang 中运行良好,gcc wandbox.org/permlink/R3dM6pQpsNR5IWje 似乎有问题

标签: c++ templates


【解决方案1】:

如果我们查看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
};

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

但允许在声明主模板的命名空间范围内,在本例中为全局命名空间范围。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多