c++ - 未能将函数专门化为函数指针

标签 c++ c++11 c++14 c++17

我正在使用 VS2015 Update 3。我有一个函数,我希望根据可调用对象的返回类型进行专门化。当可调用对象是仿函数时,一切都会按预期工作。当可调用对象是函数或函数指针时,它无法特化重载函数。我觉得我错过了一些明显的东西,但我已经一年多没有与 SFINAE 做任何事情了。

我错过了什么导致特化失败?

template <typename T>
struct S
{
    T mOp;
    template <typename = void>
    typename std::enable_if<
        std::is_same<
            std::remove_cv_t<
                std::remove_reference_t<
                    decltype(mOp())
                >
            >,
            void
        >::value
    >::type func()
    {
        std::cout << "bool" << std::endl;
    }
    template <typename = void>
    typename std::enable_if<
        std::is_same<
            std::remove_cv_t<
                std::remove_reference_t<
                    decltype(mOp())
                >
            >,
            bool
        >::value
    >::type func()
    {
        std::cout << "void" << std::endl;
    }
};

template <typename T>
auto createS(T&& t)
{
    return S<T>{ t };
}

void vfunc()
{
}
bool bfunc()
{
    return true;
}
struct vfunctor
{
    void operator()()
    {
    }
};
struct bfunctor
{
    bool operator()()
    {
        return true;
    }
};

void func()
{
    createS(bfunc).func();     // Fails to specialize func()
    createS(vfunc).func();     // Fails to specialize func()
    createS(vfunctor{}).func();
    createS(bfunctor{}).func();
}

最佳答案

这一切都不起作用,因为替换失败只是替换的直接上下文中的失败 - 并且您尝试在不依赖于直接函数模板参数的上下文中进行 SFINAE。您在 func() 中的限制基于 class 模板参数,而不是本地函数模板参数,因此这些只是一个硬错误。

最简单的方法是通过标签调度。包裹decltype(mOp())进入标签类型,然后重载:

template <class T> struct tag { };

template <typename T>
struct S
{
    T mOp;

    void func() {
        func_impl(tag<std::decay_t<decltype(mOp())>>{});
    }

    void func_impl(tag<bool> ) { std::cout << "bool\n"; }        
    void func_impl(tag<void> ) { std::cout << "void\n"; }        
};

如果您需要func()由于某种原因本身对 SFINAE 友好,那么您可以引入一个新的模板参数来伪造原始参数:

template <class..., class U=T>
auto func()
    -> decltype(func_impl(tag<std::decay_t<std::invoke_result_t<U>>>{}))
{
    return func_impl(tag<std::decay_t<std::invoke_result_t<U>>>{});
}

请注意,这必须出现在各个 func_impl 的声明之后过载。

关于c++ - 未能将函数专门化为函数指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46838311/

相关文章:

c++ - 执行我的简单函数需要多少 CPU 周期?

c++ - 如何在 QNetworkReply::deleteLater() 中调试双重删除

c++ - 为什么 C++11 不支持 'std::function<void(int, ...)>' ?

c++ - 如何修改 Dijkstra 算法以在最短路径中至少具有 X 个顶点或 K 个边

c++ - 通过作为 C++ 中函数的指针传递来访问 std::array 元素的正确方法是什么?

c++14 - 与库链接导致 char 中缺少 collat​​e facet

c++ - 如何使 2D vector 中的每个 vector 不同?

python - 将 ctypes c_void_p 转换为 C 输出参数

c++ - 模板参数包会引发错误,而显式参数不会

C++1y/C++14 : Converting static constexpr array to non-type template parameter pack?