如何传递自由格式谓词作为模板函数指针参数?

时间:2018-12-08 09:32:01

标签: c++ c++11 templates variadic-templates

我正在尝试编写一个函数,该函数通过使用自由格式谓词测试对象序列来构造位掩码:

template<typename... Args, bool(*TestingFunc)(Object, Args...)>
inline uint32_t getMask(const std::vector<Object>& objects, Args... args)
{
    uint32_t mask = 0;

    for(size_t i = 0; i < objects.size(); i++)
        if(TestingFunc(objects[i], args...))
            mask |= 1 << i;

    return mask;
}

但是,上面的代码不起作用:gcc / clang在每次调用函数时报告no matching function for call to(clang的note: candidate template ignored: invalid explicitly-specified argument for template parameter 'Args',gcc的note: template argument deduction/substitution failed:;调用为{{ 1}},谓词为getMask<int, pred1>(objects, 10),请参见下面的信息。

有一些定义明确的谓词,它们接受不同数量的特定于bool pred1(Object, int)调用的附加参数。每个谓词都是一个简单的函数。理想情况下,应该编写getMask()函数,以便我可以这样调用它:

getMask()

这是我程序中的一个热点;性能至关重要。 /* bool predicate1(Object, size_t, size_t, int, int); */ mask = getMask<predicate1>(objects, a.height(), b.width(), 10, 15); /* ... */ /* bool predicate2(Object, int, int); */ mask = getMask<predicate2>(objects, x, y); 和谓词用内联标记。该代码必须用C ++ 11(不是C ++ 14或更高版本)编写。

那么,getMask()应该如何写?

2 个答案:

答案 0 :(得分:0)

我建议您遵循标准库,仅按值传递可调用的模板化类型。如果不是函数指针,它将被内联。

template<class... Args, class F>
inline uint32_t getMask(F f, const std::vector<Object>& objects, Args... args)
{
    uint32_t mask = 0;

    for(size_t i = 0; i < objects.size(); i++)
        if(f(objects[i], args...))
            mask |= 1 << i;

    return mask;
}

如果有ctce,有一种非常简单的方法可以将函数指针转换为无状态可调用对象:
使用std::integral_constant<decltype(p), p>。在C ++ 17中,也许有一个助手。

template <auto f>
using to_type = std::integral_constant<decltype(f), f>;

getMask(to_type<checkit>(), somedata, arg0, arg1, arg2);
getMask([](auto... x){ return checkit(x...); }, somedata, arg0, arg1, arg2);

答案 1 :(得分:-1)

在c ++ 17中,您可以编写

template<auto TestingFunc, typename... Args>
inline uint32_t getMask(const std::vector<Object>& objects, Args... args)
{
    uint32_t mask = 0;

    for(size_t i = 0; i < objects.size(); i++)
        if(TestingFunc(objects[i], args...))
            mask |= 1 << i;

    return mask;
}

在C ++ 11中,您还需要执行更多操作:

首先,我们不能使用模板函数,因为它需要部分重载。因此,只需采用具有静态功能的结构:

struct Object
{   
    Object( int _val ):val{_val}{}
    int val;
};  

template <class F, F f> struct caller;

template <class Obj, class... Args, bool (* TestingFunc)(Obj, Args...)>
struct caller<bool (*)(Obj, Args...), TestingFunc>
{   
    static uint32_t Do( std::vector<Object>& objects, Args... args) 
    {
        uint32_t mask = 0;

        for(size_t i = 0; i < objects.size(); i++)
            if(TestingFunc(objects[i], args...))
                mask |= 1 << i;

        return mask;
    }
};  

bool checkit( const Object& o, int i ) 
{   
    return o.val==i;
}   

int main()
{   
    std::vector<Object> objects;
    objects.emplace_back(1);
    objects.emplace_back(2);
    objects.emplace_back(3);

// The ugly thing before c++17 is, that you have to specify the
// function type itself as a template parameter. As said: C++17
// has offered exactly the feature of auto here in template parameter lists
// to allow deduction of type from parameter.
    std::cout << caller<decltype(&checkit), checkit>::Do(objects,3) << std::endl;
}

但是我认为,耗时的事情根本不是使用函数指针。在您手动修改很多东西之前,先进行测量,测量,测量!