VS2013 上的 SFINAE 错误

SFINAE error on VS2013?

本文关键字:错误 SFINAE 上的 VS2013      更新时间:2023-10-16

我一直在尝试任何我能想到的事情来使_CallWithRightmostArgsInner函数正确失败,以便SFINAE可以正常工作,通过这次尝试,VS2013给了我错误: error C2039: 'type' : is not a member of 'std::enable_if<false,void>'

有什么想法吗? 有没有更好的替代方案? 这里的想法是,我想对函数进行函数调用,前提是函数采用 NumArgs 表示的数字或参数。 最后两个可变参数应转发给函数并返回结果。

template <typename Function, int NumArgs>
class SplitParameters {
public:
    typedef typename function_traits<Function>::result_type result_type;
    template <typename ... RightArgs>
    static result_type CallWithRightmostArgs(const Function& call, RightArgs && ... rightArgs) {
        static_assert(sizeof...(RightArgs) >= NumArgs, "Unable to make function call with fewer than minimum arguments.");
        return _CallWithRightmostArgs(call, std::forward<RightArgs>(rightArgs)...);
    }
private:
    template <typename ... RightArgs>
    static result_type _CallWithRightmostArgs(const Function& call, RightArgs && ... rightArgs) {
        return _CallWithRightmostArgsInner(call, std::forward<RightArgs>(rightArgs)...);
    }
    // note the '==' vs '!=' in these two functions.  I would assume that only one could exist
    template <typename LeftArg, typename ... RightArgs, typename std::enable_if<sizeof...(RightArgs) != NumArgs>::type* = 0>
    static result_type _CallWithRightmostArgsInner(const Function& call, LeftArg, RightArgs && ... rightArgs) {
        return _CallWithRightmostArgs(call, std::forward<RightArgs>(rightArgs)...);
    }
    template <typename LeftArg, typename ... RightArgs, typename std::enable_if<sizeof...(RightArgs) == NumArgs>::type* = 0>
    static result_type _CallWithRightmostArgsInner(const Function& call, LeftArg, RightArgs && ... rightArgs) {
        return call(std::forward<RightArgs>(rightArgs)...);
    }
};

通过将代码更改为 g++-4.8,我得到了它

    #include <iostream>
    template <class T>
    struct function_traits
    {
        typedef void result_type;
    };
    template <typename Function, int NumArgs>
    class SplitParameters {
    public:
        typedef typename function_traits<Function>::result_type result_type;
        template <typename ... RightArgs>
        static result_type CallWithRightmostArgs(const Function& call, RightArgs && ... rightArgs) {
            static_assert(sizeof...(RightArgs) >= NumArgs, 
                          "Unable to make function call with fewer than minimum arguments.");
            return _CallWithRightmostArgs(call, std::forward<RightArgs>(rightArgs)...);
        }
    private:
        template <typename ... RightArgs>
        static result_type _CallWithRightmostArgs(const Function& call, RightArgs && ... rightArgs) {
            return _CallWithRightmostArgsInner(call, std::forward<RightArgs>(rightArgs)...);
        }
        // note the '==' vs '!=' in these two functions.  I would assume that only one could exist
        template <typename LeftArg, typename ... RightArgs, class = typename std::enable_if<sizeof...(RightArgs) != NumArgs -1 >::type>
        static result_type _CallWithRightmostArgsInner(const Function& call, LeftArg, RightArgs && ... rightArgs) {
            return _CallWithRightmostArgsInner(call, std::forward<RightArgs>(rightArgs)...);
        }
        template <typename ... RightArgs, class = typename std::enable_if<sizeof...(RightArgs) == NumArgs>::type>
        static result_type _CallWithRightmostArgsInner(const Function& call, RightArgs && ... rightArgs) {
            return call(std::forward<RightArgs>(rightArgs)...);
        }
    };
    void f(int i, int j)
    {
        std::cout << i << ' ' << j << std::endl;
    }
    int main()
    {
        SplitParameters<decltype(f), 2>::CallWithRightmostArgs(f, 1, 2, 3, 4);
    }

编译器不喜欢你从_CallWithRightmostArgsInner调用_CallWithRightmostArgs,我假设你实际上是在尝试调用Inner函数。
g++ 也不喜欢在模板参数列表中将0转换为void*,所以我将其更改为 class = enable_if<...>::type

我没有详细调查它失败的原因,希望这对你来说已经足够好了。

编辑:关于被拒绝typename enable_if<...>::type* = 0,我记得std::array也有类似的问题:

    template <class T, int size>
    void f(const std::array<T,size>&){}

这个小片段本身编译得很好,但是当你这样做时:

    std::array<int,4> a;
    f(a);
    g++ gives:
    test3.cpp: In function ‘int main()’:
    test3.cpp:9:8: error: no matching function for call to ‘f(std::array<int, 4ul>&)’
         f(a);
            ^
    test3.cpp:9:8: note: candidate is:
    test3.cpp:4:6: note: template<class T, int size> void f(const std::array<T, size>&)
     void f(const std::array<T,size>&){}
          ^
    test3.cpp:4:6: note:   template argument deduction/substitution failed:
    test3.cpp:9:8: note:   mismatched types ‘int’ and ‘#‘integer_cst’ not supported by dump_type#<type error>’
         f(a);
            ^
    test3.cpp:9:8: note:   ‘std::array<int, 4ul>’ is not derived from ‘const std::array<T, size>’

事实证明,问题是我将模板声明为size参数的int,但编译器得到的是一个与int不同的std::size_t,即使您可以轻松地在它们之间进行转换。
在上面的例子中,我什至不能用= NULL替换= 0,因为这只是一个0L文字,我必须做= (void*)0才能让编译器接受它(因为默认的enable_if<true>::type类型是void)。