如何将自由形式的谓词作为模板函数指针参数传递?
How can I pass a free-form predicate as a template function pointer argument?
我正在尝试编写一个函数,通过使用自由形式的谓词测试一系列对象来构造位掩码:
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:
;调用是 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);
这是我程序中的一个热点;性能至关重要。 getMask()
并且谓词用内联标记。代码必须用 C++11(不是 C++14 或更高版本)编写。
那么,getMask()
应该怎么写呢?
从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;
}
但我认为耗时的根本不是函数指针的使用。在你手动破解很多东西之前,衡量,衡量,衡量!
我建议您遵循标准库,只按值传递模板类型的可调用对象。如果它不是函数指针,它将被内联。
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);
我正在尝试编写一个函数,通过使用自由形式的谓词测试一系列对象来构造位掩码:
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:
;调用是 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);
这是我程序中的一个热点;性能至关重要。 getMask()
并且谓词用内联标记。代码必须用 C++11(不是 C++14 或更高版本)编写。
那么,getMask()
应该怎么写呢?
从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;
}
但我认为耗时的根本不是函数指针的使用。在你手动破解很多东西之前,衡量,衡量,衡量!
我建议您遵循标准库,只按值传递模板类型的可调用对象。如果它不是函数指针,它将被内联。
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);