我在父模板中有一个嵌套模板。我希望嵌套模板的实例可以转换为从同一模板实例化的其他类(但具有不同的参数。)为此,我为嵌套模板创建了一个构造函数,可以使用不同的模板参数:
template <class T>
struct Foo
{
template <class U>
struct Bar
{
Bar() { }
template <class X, class Y>
Bar(typename Foo<X>::template Bar<Y> b)
{
}
};
};
这应该启用以下表达式来编译:
Foo<int>::Bar<int> b = Foo<char>::Bar<char>();
但 实际编译。它给出了编译器错误:
error: conversion from ‘Foo<char>::Bar<char>’ to non-scalar type ‘Foo<int>::Bar<int>’ requested
Foo<int>::Bar<int> b = Foo<char>::Bar<char>();
所以,我很困惑。为什么不编译?
答案 0 :(得分:6)
因为第二个没有创建Foo<int>::Bar<int>
。你遇到了most vexing parse。
如果您尝试使用似乎有效的b
,则会收到进一步的编译错误,表明您的b
实际上已声明为函数。
试试这个:
Foo<int>::Bar<int> b((Foo<char>::Bar<char>())); // works fine? are you sure? :)
// ^ ^
您的根本问题是参数不会被推断为†和you cannot provide them explicitly,因为我们在构造函数时不使用函数调用语法本身被调用。
为了演示,请观察以下修改过的代码,其中我用成员函数替换非默认构造函数:
template <class T>
struct Foo
{
template <class U>
struct Bar
{
Bar();
template <class X, class Y>
void foo(typename Foo<X>::template Bar<Y> b)
{}
};
};
int main()
{
//Foo<int>::Bar<int> b = Foo<char>::Bar<char>();
Foo<int>::Bar<int> i;
i.foo(Foo<char>::Bar<char>());
}
这为我们提供了更多信息,其中the key error is:
prog.cpp:11:14: note: template argument deduction/substitution failed:
prog.cpp:23:30: note: couldn't deduce template parameter ‘X’
i.foo(Foo<char>::Bar<char>());
将提供明确参数的呼叫更改为:
i.foo<char,char>(Foo<char>::Bar<char>());
成功编译;但这对我们原始代码没有帮助,因为我们无法为构造函数调用提供显式参数。
所以,我们坚持使用演绎,但不幸的是,嵌套性通过以下一系列规则为我们打破了这一点:
[C++11: 14.8.2.1/5]:
只有在类型扣除失败的情况下才会考虑这些替代方案。如果它们产生多于一个可能的推导A
,则类型推导失败。 [注意: 如果 template-parameter 未在功能模板的任何功能参数中使用,或仅使用在非推导的上下文中,不能从函数调用中推导出相应的 template-argument ,并且必须明确指定 template-argument 。 - 尾注]
[C++11: 14.8.2.5/5]:
未推断的上下文是:
- [..]
- 使用 qualified-id 指定的类型的nested-name-specifier。
- [..]
简而言之,我们不能指望X
中的Foo<X>::Bar<Y>
被推断出来,而这就是一切都崩溃的地方。所以,基本上,你不能这样做。遗憾。