SFINAE奇怪地无法使用递归模板调用

时间:2016-08-26 08:30:48

标签: c++

编辑:问题解决了,这只是错误的函数声明顺序。

当我试图解决一眼看上去非常微不足道的问题时,我偶然发现了无法解释的行为。

我想以递归方式处理任意int数组,当然我必须以某种方式停止递归。 由于模板函数(如

)无法对具体数字进行部分特化
#include <algorithm>
#include <iostream>

using namespace std;

// -------------------------------------------------------------
template<typename T, int N>
void foo(T const& param, typename enable_if<N != 0, int>::type* = 0)
{
    cout << "recursive step " << N << endl;

    /* --- This was, what I desired: --- */
    //foo<T, N - 1>(param);

    /* --- THIS IS CAUSING AN ERROR! --- */
    foo<T, 0>(param);
}

// -------------------------------------------------------------
template<typename T, int N>
void foo(T const& param, typename enable_if<N == 0, int>::type* = 0)
{
    cout << "finish recursion" << endl;
}


// =============================================================
int main()
{
    int a[5] = {0, 1, 2, 3, 4};
    foo<decltype(a), 5>(a);

    /* --- SAME CALL AS WITHIN foo(), BUT CAUSING NO ERROR! --- */
    foo<decltype(a), 0>(a);
}

),我试图用SFINAE假装这个。但是当我想从第一个调用第二个SFNIAE函数时,我得到一个编译器错误。 完整的代码示例:

{{1}}

编译器告诉我:     main.cpp:9:Fehler:'struct std :: enable_if'中没有名为'type'的类型 所以看来他以某种方式无法解决第二个功能。 但是,如果我从main()调用该函数,则不是问题。

这是我第一次参加SFINAE,我希望我没有犯过任何琐碎的错误。 感谢所有读过这篇文章的人!

2 个答案:

答案 0 :(得分:1)

我对此Clang's helpfulness感到惊喜:

main.cpp:14:5: error: call to function 'foo' that is neither visible in the template definition nor found by argument-dependent lookup
    foo(param);
    ^
main.cpp:29:5: note: in instantiation of function template specialization 'foo' requested here
    foo(a);
    ^
main.cpp:19:6: note: 'foo' should be declared prior to the call site
void foo(T const&, typename std::enable_if::type* = 0)
     ^

我的意思是,它距离登录Stack Overflow只有一步之遥并给出答案。反正。

将第二个函数的声明添加到第一个函数之上,以便您可以从其中调用它:

template<typename T, int N>
void foo(T const&, typename std::enable_if<N == 0, int>::type* = 0);

请注意,您还必须从定义中删除默认参数。

答案 1 :(得分:1)

你需要切换定义的顺序(或者在正常情况之前声明普通的情况),正常情况下看不到简单的情况,所以它不能调用它:

template<typename T, int N>
void foo(T const& param, typename enable_if<N == 0, int>::type* = 0) {
    cout << "finish recursion" << endl;
}

template<typename T, int N>
void foo(T const& param, typename enable_if<N != 0, int>::type* = 0) {
    cout << "recursive step " << N << endl;
    foo<T, N - 1>(param);
}

请注意,您可以在此处使用辅助类来避免此enable_if(并且还更改签名以便您可以让编译器推导出参数):

template<typename T, int N>
struct foo_h {
    static void call(T const& param) {
        foo_h<T, N - 1>::call(param);
    }
};


template<typename T>
struct foo_h<T, 0> {
    static void call(T const& param) {

    }
};

template<typename T, int N>
void foo(const T (&param)[N]) {
    foo_h<const T[N], N>::call(param);
}

然后:

int arr[] = {1, 2, 3, 4, 5};

foo(arr); // Automatic template parameters deduction!