如何从右到左展开参数包
How to unroll a parameter pack from right to left
我正在尝试通过递归调度到类来展开参数包。我想从右到左这样做,因为某些操作确实预先挂起。
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename R, typename... Rs>
class Foo<T, Rs..., R> {
private:
Foo<T, Rs...> foo_;
}
不幸的是,以上让我:
类模板部分专用化包含无法推导的模板参数; 这种部分专用化永远不会被使用
这对我来说似乎很奇怪,我认为即使参数已经切换了顺序,Foo<T, Rs..., R>
仍然应该与模板专业化相匹配。
我看过一些类似的问题:
具体来说,C++模板部分专用化:为什么我无法匹配可变参数模板中的最后一个类型?
但是,投票最高(未接受)的答案对我来说没有意义。当然,我知道模板参数包声明必须是声明中的最后一个,但我这样做是为了模板专用化。
我不确定为什么编译器无法Foo<T, Rs..., R>
映射到初始模板声明Foo<T...>
并在那里强制执行参数包声明顺序。
该线程上的其他答案提供了如何提取最后一个值,但这仍然不允许你进行递归参数包展开,这是这里的重点。只是不可能从右到左展开参数包吗?
下面是一个实用程序,用于使用模板参数的相反顺序来设置模板:
#include <type_traits>
#include <tuple>
template <template <typename...> typename Template, typename ...Arg>
struct RevertHelper;
template <template <typename > typename Template, typename Arg>
struct RevertHelper<Template, Arg>
{
using Result = Template<Arg>;
};
template <template <typename... > typename Template, typename Head, typename ...Tail>
struct RevertHelper<Template, Head, Tail...>
{
private:
template <typename ...XArgs>
using BindToTail = Template<XArgs..., Head>;
public:
using Result = typename RevertHelper<BindToTail, Tail...>::Result;
};
static_assert(std::is_same_v<typename RevertHelper<std::tuple, int, double>::Result, std::tuple<double, int>>, "");
因此,如果您需要使用模板包实例化Foo
Args...
被反转,您可以使用
typename RevertHelper<Foo, Args...>::Result
要按照您想要的方式执行参数包扩展,请调度到反向实现:
namespace internal {
template <typename... T>
class FooHelper;
template <typename T>
class FooHelper<T> {/* base implementation */}
template <typename L, typename R, typename... Rs>
class FooHelper<T> {
private:
Foo<T, Rs...> foo_helper_;
};
}
template <typename... T>
class Foo {
typename RevertHelper<internal::FooHelper, T...>::Result foo_helper_;
};
我不确定为什么编译器无法
Foo<T, Rs..., R>
映射到初始模板声明Foo<T...>
并在那里强制执行参数包声明顺序。
因为部分排序已经是一个非常复杂的算法,增加额外的复杂性充满了危险。有一个提案要做这项工作,其中有这样一个例子:
template <class A, class... B, class C> void foo(A a, B... b, C c); foo(1, 2, 3, 4); // b is deduced as [2, 3]
足够简单吧?现在,如果C
有一个默认参数怎么办?这是做什么的:
template <class A, class... B, class C=int> void foo(A a, B... b, C c=5);
foo(1, 2, 3, 4);
对此有两种解释:
b
被推算为包{2, 3}
,c
被推算为4
b
被推算为包{2, 3, 4}
,c
被推算为5
这是有意的?还是我们只是不允许函数参数包后的默认参数?
不幸的是,我们没有很好的包索引机制。同时,只需使用Boost.Mp11:
template <typename... T>
class Foo;
template <typename T>
class Foo<T> {/* base case implementation*/};
template <typename T, typename... Rs>
class Foo<T, Rs...> {
private:
using R = mp_back<Foo>;
mp_pop_back<Foo> foo_;
};
为了简化算法和理解,有意简化了C++模板模式中的模式匹配。
如果可能的话,看看假设的算法:
- 获取一些声明:使用
X = Foo<int, char, bool, double>
; - 编译器检查专业化:第一个是Foo-它被删除了。
- 编译器检查专业:第二个是你的
Foo<T, Rs..., R>
T
int
,我们很好。R
的可能很糟糕,让我们尝试跳过它。R
是char
,但我们在专用化参数的末尾,让我们回到 2。R
的字符R
是bool
,但我们在专用化参数的末尾,让我们回到 2。R
是char
,bool
R
double
,我们很好,选择这个
但这只是一种情况:另一种情况是将所有参数吃到最后,然后一个接一个地切断以尝试匹配它。这可能会有问题,因为这种模板专用化本质上是模棱两可的,而另一种可能的专用化在这里似乎不是歧义:
template<typename T, typename S>
class Foo<T, S> {};
- 是否可以在 RTL(从右到左)中制作控制台输出?
- 如何将函数作为参数从 C 传递到 C++ 并传回 C
- 从右到左隔离字符串.C++
- 从右到左计算当前索引中的数据结构中的元素数,并打印每个元素的计数
- 如何从右到左展开参数包
- 如何在包含 typedef 时用从右到左的规则解释变量声明
- 如何确定数字是否具有从右到左升序的数字
- 通过字符串参数从Swift到OBJ C 传递功能指针
- Boost Tribol导致C++中从右到左的条件求值
- C 将指针常数作为参数从MAIN到方法传递
- 将参数从c#传递到c++
- 如何用从右到左的语言进行输出
- 是从右到左计算的 C++11 赋值表达式
- 你如何让一个向量从右到左阅读
- 将参数从 C# 传递到C++ Dll 并返回的正确方法是什么?
- 没有已知的参数从类型到类型的转换
- 将回调参数从c#传递到非托管c++
- 将wchar_t**作为输出参数从c++发送到c#
- Outlook表单区域从右到左从c++代码
- 从右到左的阅读顺序:为什么不自动计算?