返回取决于sizeof的变量类型..参数包
Return variable type depending on sizeof... parameter pack
我希望创建一个函数,如果传递了多个模板参数,则返回一个装箱的元组,如果只传递了一个模板参数则返回未装箱的值。
例如,我希望foo<int>()
返回int
,foo<int, float>
返回类型为std::tuple<int, float>
的某物。
我为达到这个效果所做的一切努力都失败了。
考虑使用类型特征结构的以下方法:
template<typename... T>
struct return_type {
typedef std::tuple<T...> type;
};
template<>
struct return_type<int> {
typedef int type;
};
// ... insert partial specializations for other supported primitive types
template<typename... T>
auto foo() -> typename return_type<T...>::type {
if (sizeof...(T) == 1)
return zap<T...>(); // Returns something of type T, where T is the first parameter
else
return bar<T...>(); // Assume this returns a std::tuple<T...>
}
由于foo
主体中的返回类型不同,这将无法编译。
或者,以下是使用decltype
:的尝试
<template T>
T singular();
<template... T>
std::tuple<T...> multiple();
template <typename... T>
auto foo() -> decltype(sizeof...(T) == 1 ? singular() : multiple())
{
... // as above
}
这也将无法编译,因为三元运算符希望两个分支返回相同的类型。
最后,使用简单递归拆包的天真方法也失败了:
template<typename T>
T foo() { return T{}; // return something of type T }
template<typename... T>
std::tuple<T...> foo() { return bar<T...>(); // returns a tuple }
这当然会失败,因为编译器无法确定要调用哪个重载函数。
我不明白为什么这样的东西在C++11中是不可能的,因为确定返回类型所需的所有信息在编译时都是可用的。然而,我正在努力寻找什么工具可以让我做到这一点。如有任何帮助和建议,我们将不胜感激。
我通常使用一个结构进行专门化:
#include <iostream>
#include <tuple>
namespace Detail {
template <typename...Ts>
struct Foo {
typedef std::tuple<Ts...> return_type;
static return_type apply() { return return_type(); }
};
template <typename T>
struct Foo<T> {
typedef T return_type;
static return_type apply() { return return_type(); }
};
}
template <typename...Ts>
typename Detail::Foo<Ts...>::return_type foo() {
return Detail::Foo<Ts...>::apply();
}
int main ()
{
std::tuple<int, int> t = foo<int, int>();
int i = foo<int>();
}
啊,我终于休息了一下,喝了一杯(这也是经过几个小时试图找到解决方案的结果!),终于找到了答案。
答案是对最后一种方法的修改:
template<typename T>
T foo() { return zap<T>(); /* returns a T */ }
template<typename T1, typename T2, typename... Ts>
std::tuple<T1, T2, Ts...> foo() { return bar<T1, T2, Ts...>(); /* returns a tuple */ }
通过使用两个伪参数,编译器可以明确地确定要调用哪个函数。
我会使用标记调度。
template<class...Ts> struct many :std::true_type {};
template<class T>struct many :std::false_type {};
template<class...Ts> struct return_value {
typedef std::tuple< typename std::decay<Ts>::type... > type;
};
template<class T>struct return_value : std::decay<T> {};
template<typename T>
T singular( T&& t ) {
return std::forward<T>(t);
}
template<typename... Ts>
typename return_value<Ts...>::type multiple( Ts&&... ts ) {
return { std::forward<Ts>(ts)... };
}
template<typename...T>
typename return_value<T...>::type worker(std::false_type, T&&...t ) {
static_assert( sizeof...(T)==1, "this override is only valid with one element in the parameter pack" );
return singular(std::forward<T>(t)...);
}
template<typename...Ts>
typename return_value<Ts...>::type worker(std::true_type, Ts&&...t) {
return multiple(std::forward<Ts>(t)...);
}
template<class...Ts>
auto foo(Ts&&... t)
-> decltype(worker( many<Ts...>(), std::declval<Ts>()...) )
{
return worker(many<Ts...>(), std::forward<Ts>(t)...);
}
然后我会添加完美的转发。
我发现对过载的推理比对专业化的推理更容易。
相关文章:
- 在 c++ 中的模板实例化中使用带有构造函数的类作为类型参数
- 如何解决一元"*"(有"字符")错误的无效类型参数?
- "std::shared_ptr":不是参数"_Ty"的有效模板类型参数
- 具有可变参数非类型参数的模板专用化
- 函数类型参数的模板参数推导
- PowerShell 使用结构类型参数调用 C++ DLL 的导出函数
- 对于非常量指针类型的参数,未调用具有常量指针模板类型参数的功能
- 为模板传递非类型参数 agument
- 为什么带有类型参数的运算符 () 可以应用于 result_of 上下文中的类型?
- 使用其他模板类型参数作为要在函数签名中使用的类型别名声明
- 如何避免具有相同类型参数的函数中的错误
- 将内置类型变量传递给只有一个类类型参数的"+"运算符函数时自动类型转换的构造函数
- c++非类型参数包扩展
- 如何实现对参数顺序不可知的std::same_as的广义形式(即对于两个以上的类型参数)
- 在不同的模板参数包之间分发非类型参数包
- 如何在使用容器和字符串时强制使用显式分配器类型参数
- 错误:一元"*"的类型参数无效(具有"int"):使用 mergesort 计算
- EXPECT_CALL具有 unique_ptr 引用类型参数的模拟函数
- 作为模板类型参数,为什么 type[N] 与其专用版本不匹配----模板<类 T>类 S<T[]>
- C++ 模板:重载时找不到基类类型参数方法