C++11如何从可变参数模板类型(如std::tuple)提取参数包?
问题翻译
在C++11环境下,如何将模板类型的可变参数提取为参数包?假设存在模板特化类型Argument_t,其定义如下:
... template<typename F> using Argument_t = ArgumentType<F>::type; // 该类型为std::tuple<Args...>
现需在结构体SomeStruct中使用该模板特化,将模板参数的签名复制到方法中,示例代码如下:
template<typename F> struct SomeStruct { // 如何让此处的Args...为Argument_t<F>中的参数包 void some_method(Args... args) { ... // 需要能访问some_member_data }; ... static int some_member_data; }
请问如何从std::tuple<Args...>类型中提取出Args...参数包?除了让Argument_t返回std::tuple<Args...>之外,是否有更优方案?
解决方案
一、从std::tuple<Args...>中提取参数包
C++11无法直接从tuple类型中解包参数包,需通过模板偏特化实现:
- 先声明主模板
SomeStruct,再针对std::tuple<Args...>编写偏特化版本,直接获取参数包Args... - 让主模板继承自偏特化版本,实现对原模板参数
F的适配
代码示例:
#include <tuple> // 假设已定义的ArgumentType和Argument_t template<typename F> struct ArgumentType; // 示例:针对普通函数类型的特化 template<typename R, typename... Args> struct ArgumentType<R(Args...)> { using type = std::tuple<Args...>; }; template<typename F> using Argument_t = typename ArgumentType<F>::type; // 主模板声明 template<typename F> struct SomeStruct; // 偏特化:处理tuple类型,直接提取参数包Args... template<typename... Args> struct SomeStruct<std::tuple<Args...>> { void some_method(Args... args) { // 正常访问静态成员 some_member_data = 42; } static int some_member_data; }; // 主模板定义:继承自针对Argument_t<F>的偏特化版本 template<typename F> struct SomeStruct : SomeStruct<Argument_t<F>> {}; // 静态成员初始化 template<typename... Args> int SomeStruct<std::tuple<Args...>>::some_member_data = 0; // 测试用例 void test_func(int, double, const char*); int main() { SomeStruct<decltype(test_func)> obj; obj.some_method(1, 3.14, "hello"); return 0; }
二、更优方案:直接提取参数包,无需中转tuple
如果可以调整ArgumentType的设计,完全不需要通过tuple中转,直接从目标函数/可调用类型中提取参数包,更高效且直接:
方案1:直接特化SomeStruct适配函数类型
// 直接针对函数类型特化SomeStruct template<typename F> struct SomeStruct; template<typename R, typename... Args> struct SomeStruct<R(Args...)> { void some_method(Args... args) { some_member_data = 123; } static int some_member_data; }; // 静态成员初始化 template<typename R, typename... Args> int SomeStruct<R(Args...)>::some_member_data = 0; // 测试用例 void test_func(int, double, const char*); int main() { SomeStruct<decltype(test_func)> obj; obj.some_method(1, 3.14, "hello"); return 0; }
方案2:通过ArgumentType提供参数包传递能力
如果必须保留ArgumentType结构,可让它通过模板模板参数直接传递参数包:
template<typename F> struct ArgumentType; template<typename R, typename... Args> struct ArgumentType<R(Args...)> { // 用模板模板参数将参数包传递给其他模板 template<template<typename...> class T> using apply = T<Args...>; }; // 内部结构体,接收参数包 template<typename... Args> struct SomeStructImpl { void some_method(Args... args) { some_member_data = 456; } static int some_member_data; }; // 主模板通过ArgumentType提取参数包,继承自SomeStructImpl template<typename F> struct SomeStruct : ArgumentType<F>::template apply<SomeStructImpl> {}; // 静态成员初始化 template<typename... Args> int SomeStructImpl<Args...>::some_member_data = 0; // 测试用例 void test_func(int, double, const char*); int main() { SomeStruct<decltype(test_func)> obj; obj.some_method(1, 3.14, "hello"); return 0; }
该方案避免了tuple的中转开销,类型推导更直接,可读性更强。
内容的提问来源于stack exchange,提问作者lighthouse
相关产品推荐
相关产品推荐

