在C ++中,有一个函数本地类型的函数是可以的:
int main() {
struct S { static void M(const S& s) { } };
S s;
S::M(s);
}
但不能正常使用模板:
template<typename T> void Foo(const T& t) { }
int main() {
struct S { } s;
Foo(s); // Line 5: error: no matching function for call to 'Foo(main()::S&)'
}
14.3.1 paragraph 2 in the c++ standard.
没有链接的类型[...]不能用作模板类型参数的模板参数
为什么C ++不允许这样做?
到目前为止我听到的最好的解释是内部类型没有链接,这可能意味着将它们作为arg的函数必须没有链接。但我没有理由看到模板实例化必须具有链接。
P.S。请不要只说“thats not allowed because the standard says it's not”
答案 0 :(得分:7)
我认为预见到的困难是Foo<T>
的两个实例实际上意味着完全不同的事情,因为T
对于两者都不一样。相当多的模板早期实现(包括cfront)使用了模板实例化的存储库,因此当/如果发现该类型的实例化尚未存储在存储库中时,编译器可以自动实例化所需类型的模板。
为了使用本地类型工作,存储库不仅能够存储实例化模板的类型,而且还需要为类型创建完整的“路径”。实例。虽然这可能是可能的,但我认为它被视为很少额外的工作(如果有的话)。
从那时起,规则已经发生了很大变化,以至于编译器已经被要求做一些几乎相同的事情,在不同的地方(包括跨TU)在同一类型上查找(和合并)实例化,以便{{{{ 1}}(例如)不违反ODR。基于该实现,在(当前草案)C ++ 0x中放宽了限制(您仍然无法在本地类型上实例化模板类,但您可以使用本地类型作为模板函数的参数)
答案 1 :(得分:3)
我猜这是因为它需要在函数范围内有效地实例化模板,因为这是可见的类型。但是,同时,模板实例化应该表现为它们位于定义模板的范围内。我确信这有可能以某种方式处理,但如果我是对的,标准组织决定不对编译器编写者施加这种负担。
类似的决定是vector<vector<int>>
每个标准的语法无效的原因;检测到构造需要编译器词法分析器和解析器阶段之间的某些交互。然而,这种情况正在发生变化,因为C ++ 0x标准民众发现所有编译器都在检测它,无论如何都要发出合理的错误信息。
我怀疑,如果要证明允许这种构造实现起来微不足道,并且它没有在语言范围规则中引入任何含糊之处,那么有朝一日你可能会看到标准也发生了变化。