如何在另一个类模板中定义完全专业化类的构造函数

时间:2019-07-04 17:37:15

标签: c++ templates language-lawyer c++17

我有一个包含另一个类模板的类模板,并且内部模板具有显式的专业化:

template <typename Outer>
struct ContainingClass {
  template <typename T>
  struct Rule {
    Rule(T value);

    // ... other members ...
  };

  template <>
  struct Rule<void> {
    Rule();

    // ... different members than the non-void Rule<T> ...
  };
};

我已经为通用Rule和专用template <typename Outer> template <typename T> ContainingClass<Outer>::Rule<T>::Rule(T value) { } template <typename Outer> ContainingClass<Outer>::Rule<void>::Rule() { } 定义了构造函数:

error: nested name specifier 'ContainingClass<Outer>::Rule<void>::' for declaration does not refer into a class, class template or class template partial specialization
ContainingClass<Outer>::Rule<void>::Rule() { }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^

但是Clang不喜欢专门类的构造函数:

ContainingClass<Outer>

对此我感到困惑,因为它“引用”了{em>是类(ContainingClass类模板的实例)ContainingClass。我怀疑我需要为此更改语法,但是尚不清楚。如何定义该构造函数?

(如果我删除Rule并将Rule放在命名空间范围内,这是可行的,但是我需要在Outer中包含其他依赖于Rule类型的东西。可以给Outer自己的Rule模板参数,但这会使使用此类的代码变得更尴尬,所以我想尽可能避免它,而且我知道我可以定义struct Rule<void>类主体中的构造函数内联,但是我想了解为什么单独的定义不起作用。)

如果有关系,我将同时使用Ubuntu 19.04中的Clang 8.0和Mac上的Apple的“ clang-1001.0.46.4”。 (我也尝试过Ubuntu的GCC 8.3,但是由于GCC bug #85282template <> struct Rule<void>本身的定义上的“非命名空间范围的显式专业化”而在其他地方失败了。)

编辑后进行了澄清:我的错误不是关于在ContainingClass中使用Rule专长。这是C ++ 14限制(defect CWG 727)的主题,此限制通过添加虚拟模板参数来解决,因此模板仅是部分专用而非完全专用。我相信在C ++ 17中已经解除了限制,并且//child export default: { data() { return { submit_method: { type: Function } } }, methods: { open(type) { if(type == 'newFolder') { this.$refs.newFolder.show() this.submit_method = this.exportFile() } else { this.$refs.olderOmbudsman.show() } }, exportFile() { if ( this.doc.origin.id != null ) { window.open(`${window.globals.API_SERVER}/ombudsman/doc/?page=${this.doc.page}&origin=${this.doc.origin.id}`, '_target') }else{ alert("Choose the origin!"); } } }, activated() { this.$emit('export-ombudsman', submit_method) } } 类本身的专业化在Clang中也可以正常工作(尽管GCC有此错误)。因此,我认为虚拟参数变通方法不是这里的正确解决方案,但请告诉我是否有误,并且在C ++ 17中对此仍然有限制。

1 个答案:

答案 0 :(得分:5)

您不能在命名空间范围内声明模板的模板成员的专业化成员。

为避免此限制,您可以使用c ++ 14及更早版本所必需的解决方法,其中包括使用部分专业化而不是完全专业化:

def destroy_multiple
  attachments = ActiveStorage::Attachment.where(id: params[:deleted_img_ids])
  attachments.map(&:purge)
end

在C ++ 17中,仍然不可能在名称空间范围内声明类模板的特殊化成员(的成员),请参见[temp.expl.spec]/17in the C++14 standard存在相同的段落。

C ++ 17的变化是,我们可以在封闭的类模板定义中声明成员的特殊化:

  

显式专门化应在包含专门化模板的命名空间中声明。[...]

  

可以在可以定义相应主模板的任何范围内声明显式专业化。[...]