Why does the second version compile?
Because the second one doesn't create a Foo<int>::Bar<int>
. You've run into the most vexing parse.
Had you attempted you use the b
that appears to work, you'd have received further compiler errors showing that your b
is in fact declared as a function.
Try this:
Foo<int>::Bar<int> b((Foo<char>::Bar<char>())); // works fine? are you sure? :)
// ^ ^
Your root problem is that the arguments will not be deduced†, and you cannot provide them explicitly because we do not use function-call syntax per se when a constructor is invoked.
† Why won't they be deduced?
To demonstrate, observe the following modified code where I replace the non-default constructor with a member function:
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>());
}
This gives us some more information to go on, wherein 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>());
Changing the call, providing explicit arguments, to:
i.foo<char,char>(Foo<char>::Bar<char>());
yields a successful compilation; but this doesn't help us in our original code, as we cannot provide explicit arguments to a constructor invocation.
So, we're stuck with deduction, but unfortunately the nestedness breaks this for us through the following series of rules:
[C++11: 14.8.2.1/5]:
These alternatives are considered only if type deduction would otherwise fail. If they yield more than one possible deduced A
, the type deduction fails. [ Note: If a template-parameter is not used in any of the function parameters of a function template, or is used only in a non-deduced context, its corresponding template-argument cannot be deduced from a function call and the template-argument must be explicitly specified. —end note ]
[C++11: 14.8.2.5/5]:
The non-deduced contexts are:
In short, we cannot expect the X
in Foo<X>::Bar<Y>
to be deduced, and that's where everything breaks down. So, basically, you can't do this. Sorry.