【发布时间】:2019-04-08 09:01:38
【问题描述】:
我正在摆弄模板元编程,特别是类型序列和处理这些序列的类似 STL 的算法。我遇到的一件事是谓词的转换,例如通过绑定它们的参数之一
我认为如果不先提供一些背景信息,就很难描述我的问题。这是一个例子:
#include <type_traits>
// Type sequence
template<class... T>
struct typeseq
{
static constexpr size_t Size = sizeof...(T);
};
// Some algorithm
template<class TS, template<class...> class P>
using remove_if = /* ... some template logic ... */;
// Usage example:
using a = typeseq<int, float, char*, double*>;
using b = remove_if<a, std::is_pointer>; // b is typeseq<int, float>
如此处所示,remove_if 需要一个谓词,该谓词用作删除算法的预言,以确定要删除哪些元素。当我们处理元编程时,它采用模板模板参数的形式。 (注意P在这里使用可变参数模板参数。虽然我期待一元模板,但早期版本的C++有一个限制,可变参数模板参数不能用作非可变模板参数,严格限制谓词转换。) 它要求谓词在实例化时解析为具有嵌套编译时间value 成员的类型,该成员可转换为bool .
一切都很好,但假设您要删除所有可转换为int 的类型。显然,std::is_convertible 是一个二元谓词,但上面的remove_if 需要一个一元谓词。我们只需要将第二个模板参数固定为int。让我们定义一个bind2nd:
template<template<class, class...> class P, class BIND>
struct bind2nd
{
template<class T1, class... Tn> using type = P<T1, BIND, Tn...>;
};
// and now we should be able to do:
using c = remove_if<ts, bind2nd<std::is_convertible, int>::type>; // c is typeseq<char*, double*>;
不幸的是,这无法在最新的 Clang 和 MSVC++ 上编译。显然,问题是 Tn... 到 std::is_convertible<T1, BIND, Tn...> 的包扩展,而 std::is_convertible 只有 2 个模板参数。在实践中包是空的似乎并不重要(isolated example)
我宁愿不为传递给bind2nd 的谓词的任何必需数量提供“重载”。有没有办法在上面的bind2nd 中检测P 的数量? GCC 允许我为P 的非可变版本部分专门化它:
template<template<class, class> class P, class BIND>
struct bind2nd<P, BIND>
{
template<class T1> using type = P<T1, BIND>;
};
但不幸的是,首先抱怨的不是 GCC。我也怀疑这种部分专业化的一致性。有没有解决的办法?是否可以检测模板模板参数的实际数量,并根据该信息做一些不同的事情?
【问题讨论】:
标签: c++ templates c++17 variadic-templates