嵌套模板和参数推导

3

可能是重复问题:
解决非推断上下文的方法

GCC无法为这个“简单”的函数推导参数。有没有办法帮助编译器一点?

template<int a> struct A
{
    template<int b> struct B
    {
    };
};

template<int a, int b> void test(typename A<a>::template B<b> param) { }

int main()
{
    A<1>::B<2> b;

    test<1,2>(b); // works
    test(b);      // doesn't work
}

来自GCC 4.7.1的错误信息:

test.cpp: In function 'int main()':
test.cpp:15:8: error: no matching function for call to 'test(A<1>::B<2>&)'
test.cpp:15:8: note: candidate is:
test.cpp:8:29: note: template<int a, int b> void test(typename A<a>::B<b>)
test.cpp:8:29: note:   template argument deduction/substitution failed:
test.cpp:15:8: note:   couldn't deduce template parameter 'a'

@BoPersson:我同意这个问题与之密切相关,但由于这个问题涉及到嵌套模板,那里提供的答案不适用。 - Vaughn Cato
@BoPersson:我的错。将函数设置为友元模板函数确实有效。在某些情况下,这可能是更好的解决方案。 - Vaughn Cato
1个回答

5
虽然看起来这是一个简单的推断,但你希望编译器做的事情实际上在一般情况下会非常复杂和缓慢,并且它不受C++支持。
解决这个问题的一种方法是创建另一个非嵌套类,将所有模板参数放在一个地方。然后通过继承它来使它看起来像一个嵌套类:
template<int a,int b> struct A_B {
  /* define your class here */
};

template<int a> struct A
{
    template<int b> struct B : A_B<a,b> {/*nothing here*/};
};

template<int a, int b> void test(A_B<a,b> param) { }

int main()
{
    A<1>::B<2> b;

    test<1,2>(b); // works
    test(b);      // works too
}

C++11还支持模板别名,这使得代码更加简洁,虽然目前还没有被广泛支持:

template<int a> struct A
{
    template<int b> using B = A_B<a,b>;
};

这个问题与以下问题密切相关:

非推导上下文的解决方法

那里提供的答案也适用于您的情况。如果您可以使您的函数成为一个友元,那么您可以这样做:

template<int a> struct A
{
    template <int b>
    struct B
    {
    };

    template <int b>
    friend void test(B<b> param)
    {
    }
};

一般情况下,param 会受到切片或请求转换的影响(如果通过引用或指针传递)。 - Rost
@Rost:同意,它将切片。我已经添加了一条注释,以使得没有任何内容应该位于派生嵌套类中更加清晰。不过,我不明白为什么指针和引用需要进行转换。 - Vaughn Cato
在这种情况下,将 B 定义为嵌套在 A 中并没有太多意义 - 它仍然会在全局范围内重复,并且无法使用在 A 中定义的任何类型/成员... - Rost
@Rost:我认为这通常是正确的,但有时你只是想要一个嵌套的类型来使命名更简单。 - Vaughn Cato

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接