嵌套模板需要显式构造

Nested template requires explicit construction?

本文关键字:嵌套      更新时间:2023-10-16

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

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

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

为什么第二个版本会编译?

因为第二个不会创建Foo<int>::Bar<int>.您遇到了最令人烦恼的解析。

如果您尝试使用看似有效的b,您将收到进一步的编译器错误,显示您的b实际上已声明为函数。

试试这个:

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

您的根本问题是不会推导参数并且您无法显式提供它们,因为我们在调用构造函数时本身不使用函数调用语法。

<小时 />

为什么不推断它们?

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

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]: 只有当类型推断失败时,才会考虑这些替代方案。如果它们产生多个可能的推导A,则类型推导失败。[ 注意:如果模板参数未在函数模板的任何函数参数中使用,或者仅在非推导上下文中使用,则无法从函数调用中推导出其相应的模板参数,并且必须显式指定模板参数。

[C++11: 14.8.2.5/5]: 非推导上下文是:

  • [..]
  • 使用限定 id 指定的类型的嵌套名称说明符
  • [..]

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