包含可变参数包的第一个可转换类型的别名的结构
Struct that contains an alias to the first convertible type of a variadic pack
我有typename T1
,我有一个参数包typename... Variadic
。
我想创建一个结构,其中包含一个 using 别名,using Type = ...
到参数包中的第一个类型,T1
可以转换为该类型。到目前为止,我已经尝试了以下方法:
template<typename T1, typename T2, typename... Variadic>
struct VariadicConvertibleType
{
using Type = std::enable_if<std::is_convertible<T1, T2>::value, T2>::type;
};
这可能是对前两种类型使用 SFINAE 的潜在解决方案,但我需要使用递归将其扩展到包中的所有类型。到目前为止,我的所有尝试都失败了,因为您无法使用别名声明来放置条件。否则可以使用与此类似的内容:
template<typename T1, typename T2, typename... Variadic>
struct VariadicConvertibleType
{
using Type = std::is_convertible<T1, T2>::value ? T2 : VariadicConvertibleType<T1, Variadic...>::Type;
};
我可以使用最多(包括(C++14 的所有内容来实现解决方案。不过,除了标准库之外,我不能使用任何其他东西。
你可以使用 std::conditional,像这样:
template<typename T1, typename T2, typename... Variadic>
struct VariadicConvertibleType
{
using type = std::conditional_t<std::is_convertible<T1, T2>::value, T2, typename VariadicConvertibleType<T1, Variadic...>::type>;
};
template<typename T1, typename T2>
struct VariadicConvertibleType<T1, T2>
{
static_assert(std::is_convertible<T1, T2>::value);
using type = T2;
// Alternative base-case
// using type = std::conditional_t<std::is_convertible<T1, T2>::value, T2, T1>;
};
我提供了两个基本案例(评论中的替代方案(。 主要的(我的东西是你想要的(使用 (C++14(static_assert
如果T1
不可转换为Variadic
中的任何类型。在这种情况下,替代基本情况将type
设置为T1
。
测试
#include <iostream>
#include <type_traits>
#include <typeinfo>
int main()
{
using my_type_1 = typename VariadicConvertibleType<int, double, float>::type;
std::cout << typeid(my_type_1).name() << 'n'; // double
using my_type_2 = typename VariadicConvertibleType<int, int*, float>::type;
std::cout << typeid(my_type_2).name() << 'n'; // float
using my_type_3 = typename VariadicConvertibleType<int, int*, float*>::type;
std::cout << typeid(my_type_3).name() << 'n'; // Complile error with the primary base-case, and int with the alternative base-case.
}
std::conditional
的问题在于,它需要你提供给它的两种类型都得到很好的定义。为了规避这一点,您需要在此过程中引入一种间接寻址。
为此,我们将有一个帮助程序模板,该模板给定一个布尔值,将定义类型或回退到下一个元素。
namespace details {
template <bool B, typename T, typename... Args>
struct FirstConvertibleImpl;
template <typename T, typename U, typename... Args>
struct FirstConvertibleImpl<true, T, U, Args...> {
using type = U;
};
template <typename T, typename U, typename V, typename... Args>
struct FirstConvertibleImpl<false, T, U, V, Args...> {
using type = typename FirstConvertibleImpl<std::is_convertible<T, V>::value, T, V, Args...>::type;
};
}
如果给定的类型不会导致有效的转换,这显然会发出错误,因为我们不在乎定义"无效"的情况(FirstConvertibleImpl<false, T1, T2>
没有实现任何类型的T1, T2
(
现在我们制作了一个更高级别的接口,以便更清晰地使用:
template <typename T, typename... Args>
struct FirstConvertibleInPack;
template <typename T, typename U, typename... Args>
struct FirstConvertibleInPack<T, U, Args...> {
using type = typename details::FirstConvertibleImpl<std::is_convertible<T, U>::value, T, U, Args...>::type;
};
同样,我们不关心定义Args... = []
的情况,因为这些案例无论如何都是格式不正确的。
现场演示可以在Coliru上找到。
当然,您可以更深入地抽象它,并通过允许应用您喜欢的任何二元特征来使此示例更加通用。
- 继承模板类中的类型别名
- 为什么 GCC 在使用类型别名时处理 const reinterpret_cast不同?
- 类作用域的类型别名"using":[何时]方法中的用法可以先于类型别名?
- 如何使用类型别名从模板化类中隐藏模板列表
- 如何检测类型类型别名?
- C++类型别名,其中值被替换
- 如何为流输出运算符提供重载<<模板'using'类型别名?
- 通过类型别名从构造函数转发模板推导
- C++中的严格别名规则和类型别名
- 使用其他模板类型参数作为要在函数签名中使用的类型别名声明
- 什么是C++中的类型别名?
- 如何在不违反类型别名规则的情况下解释消息负载?
- 在模板派生类中继承具有类型别名的构造函数
- 类型别名允许分配任意指针,尽管 int* 是必需的
- 使用类型别名,例如使用 A = int(int)
- 模板类函数指针类型别名
- 类型别名和类似类型
- 泛型类型别名,它们彼此不兼容
- 具有类型别名的循环依赖项
- 为什么模板引用类型不能用作模板类型别名参数?