3

我正在为 C++11 开发“LINQ to Objects”库。我想做这样的事情:

// filtering elements by their value
arr.where( [](double d){ return d < 0; } )

// filtering elements by their value and position
arr.where( [](double d, int i){ return i%2==0; } )

我很想写arr.where_i( ... )- 这很难看。所以我需要通过 lambda 类型重载函数/方法...

这是我的解决方案:

template<typename F>
auto my_magic_func(F f) -> decltype(f(1))
{
    return f(1);
}

template<typename F>
auto my_magic_func(F f, void * fake = NULL) -> decltype(f(2,3))
{
    return f(2,3);
}

int main()
{
    auto x1 = my_magic_func([](int a){ return a+100; });
    auto x2 = my_magic_func([](int a, int b){ return a*b; });
    // x1 == 1+100
    // x2 == 2*3
}

是 SFINAE 解决方案吗?你能给我什么建议?

4

2 回答 2

3

也许是可变的:

#include <utility>

template <typename F, typename ...Args>
decltype(f(std::declval<Args>()...) my_magic_func(F f, Args &&... args)
{
    return f(std::forward<Args>(args)...);
}

编辑:您也可以使用typename std::result_of<F(Args...)>::type返回类型,它做同样的事情。

于 2012-05-12T10:30:27.527 回答
2

您当然希望 SFINAE 在您的解决方案中。一般来说,结果看起来像:

template<
    typename Functor
    , typename std::enable_if<
        special_test<Functor>::value
        , int
    >::type = 0
>
return_type
my_magic_func(Functor f);

template<
    typename Functor
    , typename std::enable_if<
        !special_test<Functor>::value
        , int
    >::type = 0
>
return_type
my_magic_func(Functor f);

这样任何时候只有一个过载会处于活动状态——现在剩下的就是精心设计它special_test以获得我们想要的行为。这是一种谨慎的平衡行为,因为您不希望测试过于具体;否则我们失去了一般性。编写通用代码时相当可惜。您没有提供太多信息(例如,您是否对支持 lambdas 非常感兴趣?单态函子?多态函子?),但我现在假设我们可以访问与您的示例value_type相对应的别名。double

因此,这是一个示例条件,它将检查给定类型是否为 Callable (这是一个标准概念)并带有签名bool(value_type);即它是一种谓词:

template<typename Functor, typename ValueType>
struct is_unary_predicate {
    typedef char (&accepted)[1];
    typedef char (&refused)[2];

    void consume(bool);

    template<
        typename X
        , typename Y
        , typename = decltype( consume(std::declval<X>()(std::declval<Y>())) )
    >
    accepted
    test(X&&, Y&&);

    refused test(...);

    static constexpr bool value =
        sizeof test(std::declval<Functor>(), std::declval<ValueType>())
        == sizeof(accepted);
};

就我个人而言,我有一个is_callable<F, Signature>特点,所以我只需要编写类似的东西template<typename Functor, typename ValueType> using is_unary_predicate = is_callable<Functor, bool(ValueType)>;(同样我可以有一个is_binary_predicate别名,而不是让第二个重载my_magic_func成为一个包罗万象的东西)。也许您希望在 SFINAE 的未来使用中使用类似的特征(尽管在没有可变参数模板的情况下编写可能会有些痛苦)。

于 2012-05-12T13:54:28.340 回答