嵌套模板需要显式构造吗?

时间:2013-10-26 22:00:48

标签: c++

我在父模板中有一个嵌套模板。我希望嵌套模板的实例可以转换为从同一模板实例化的其他类(但具有不同的参数。)为此,我为嵌套模板创建了一个构造函数,可以使用不同的模板参数:

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

所以,我很困惑。为什么不编译?

1 个答案:

答案 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]:未推断的上下文是:

     

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