可变参数模板中递归模板函数的终止问题

时间:2017-07-05 13:14:33

标签: c++ recursion variadic-templates

我正在尝试创建一个实用程序类,它将在列表中的所有类上调用特定函数。这背后的目的是在类的层次结构中自动化反射元素。

我使用Visual Studio 2015编译一些C ++代码,并且当递归模板函数展开时我收到编译错误,因为编译器在区分递归函数和终止函数时遇到问题。

我已经将课程的核心提取到一个简单的测试用例中:

error C2668: 'Meta<C,B,A>::callOnAllClasses': ambiguous call to overloaded function
could be 'void Meta<C,B,A>::callOnAllClasses<T,A,>(const T &)'
or       'void Meta<C,B,A>::callOnAllClasses<T,A>(const T &)'

在Visual Studio 2015中编译时,会导致以下错误:

{{1}}

我之前从未使用过变量模板,所以我有点不知道为什么会出错。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:2)

您的问题可以按照以下方式最小化:

template< typename ... Bases >
struct Meta
{
    template< typename T >
    void call(const T& val)
    {
        callOnAllClasses<T, Bases...>(val);
    }

    template< typename T, typename HeadClass >
    void callOnAllClasses(const T& val)
    {

    }

    template< typename T, typename HeadClass, typename ... TailClasses >
    void callOnAllClasses(const T& val)
    {
        callOnAllClasses<T, TailClasses...>(val);
    }
};

struct C : Meta<int, int, int> { };

int main()
{
    C{}.call(5);
}

TailClasses为空时,这两个签名对编译器都不明确:

template< typename T, typename HeadClass >
void callOnAllClasses(const T& val);

template< typename T, typename HeadClass, typename ... TailClasses >
void callOnAllClasses(const T& val);

在递归情况下添加额外的模板参数有助于编译器在TailClasses为空时消除变量和非变量重载之间的歧义。

template< typename T, typename HeadClass, typename T1, typename ... TailClasses >
void callOnAllClasses(const T& val)
{
    auto pObj = dynamic_cast<HeadClass*>(this);
    if ( pObj )
        pObj->HeadClass::doSomething(val);
    callOnAllClasses<T, T1, TailClasses...>(val);
}

live example on godbolt

相关问题