【发布时间】:2019-07-04 17:37:15
【问题描述】:
我有一个包含另一个类模板的类模板,而内部模板有一个明确的特化:
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() { }
但 Clang 不喜欢专用类的构造函数:
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() { }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
我对此感到困惑,因为它“引用”ContainingClass<Outer>,它是一个类(ContainingClass 类模板的一个实例)。我怀疑我需要为此更改语法中的某些内容,但不清楚是什么。如何定义这个构造函数?
(如果我删除 ContainingClass 并将 Rule 放在命名空间范围内,它会起作用,但我需要在 Rule 中有其他依赖于 Outer 类型的东西。我可以给 Rule 它自己的 @ 987654335@ 模板参数,但这会使使用此类的代码变得更加尴尬,所以如果可能的话,我想避免它。而且我知道我可以在 Rule 类主体中内联定义构造函数,但是我想了解为什么单独的定义不起作用。)
以防万一,我在 Ubuntu 19.04 中使用 Clang 8.0,在 Mac 上使用 Apple 的“clang-1001.0.46.4”。 (我也尝试过 Ubuntu 的 GCC 8.3,但由于 GCC bug #85282 导致在不同的地方失败——struct Rule<void> 本身的定义中的“非命名空间范围内的显式专业化”。)
编辑澄清:我的错误不是关于在ContainingClass 中使用template <> struct Rule<void> 专业化。这是 C++14 限制 (defect CWG 727) 的主题,可以通过添加虚拟模板参数来解决此问题,因此模板只是部分专业化而不是完全专业化。我相信 C++17 中的限制已经解除,Rule 类本身的专业化在 Clang 中运行良好(尽管 GCC 有错误)。所以我认为虚拟参数的解决方法在这里不是正确的解决方案——但如果我弄错了,请告诉我,C++17 对此仍有限制。
【问题讨论】:
-
@krisz,该限制存在于 C++14 中,但已在 C++17 中解除,这不是我得到的错误。 (由于我提到的错误,在 GCC 中除外。)
标签: c++ templates language-lawyer c++17