2

I have a nested template inside a parent template. I'd like instances of the nested template to be convertible to other classes instantiated from the same template (but with different parameters.) To do this, I create a constructor for the nested template that can take different template parameters:

template <class T>
struct Foo
{

    template <class U>
    struct Bar
    {
        Bar() { }

        template <class X, class Y>
        Bar(typename Foo<X>::template Bar<Y> b)
        {

        }
    };

};

This should enable the following expression to compile:

Foo<int>::Bar<int> b = Foo<char>::Bar<char>();



However, it doesn't actually compile. It gives the compiler error:

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>();

So, I'm confused. Why doesn't this compile?

4

1 回答 1

6

为什么第二个版本编译?

因为第二个不会创建Foo<int>::Bar<int>. 您遇到了最令人头疼的 parse

如果您尝试使用b似乎有效的方法,您会收到更多编译器错误,表明您实际上b已声明为函数。

尝试这个:

Foo<int>::Bar<int> b((Foo<char>::Bar<char>()));  // works fine? are you sure? :)
//                   ^                      ^

您的根本问题是不会推断出参数†</sup>,并且您不能显式提供它们,因为在调用构造函数时我们本身不使用函数调用语法。


†</sup>为什么不推导出来?

为了演示,请观察以下修改后的代码,其中我将非默认构造函数替换为成员函数:

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>());
}

这为我们提供了更多信息,其中关键错误是

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]:仅当类型推导失败时才考虑这些替代方案。如果它们产生多个可能的 deduced A,则类型推导失败。[ 注意: 如果一个模板参数没有在函数模板的任何函数参数中使用,或者仅在非推导上下文中使用,则不能从函数调用和模板参数中推导出其对应的模板参数必须明确指定。 ——尾注]

[C++11: 14.8.2.5/5]:未推断的上下文是:

简而言之,我们不能期望推断出Xin Foo<X>::Bar<Y>,这就是一切都崩溃的地方。所以,基本上,你不能这样做。对不起。

于 2013-10-26T22:11:09.613 回答