这是一个小系统,它可以智能地将变量转换为 Ts... 类型序列,这样变量隐式转换到的列表 Ts... 中的第一个元素就是选择的元素:
namespace details {
template<class...>struct types{using type=types;};
template<class U, class Types, class=void>
struct smart_cast_t:std::false_type {
using type=U;
template<class A>
U operator()(A&& a)const{return std::forward<A>(a);}
};
template<class U, class T0, class...Ts>
struct smart_cast_t<
U, types<T0, Ts...>,
typename std::enable_if<std::is_convertible<U, T0>::value>::type
>:std::true_type
{
using type=T0;
template<class A>
T0 operator()(A&& a)const{return std::forward<A>(a);}
};
template<class U, class T0, class...Ts>
struct smart_cast_t<
U, types<T0, Ts...>,
typename std::enable_if<!std::is_convertible<U, T0>::value>::type
>:smart_cast_t< U, types<Ts...> >
{};
}
template<class... Ts, class U>
auto smart_cast( U&& u )
-> decltype(details::smart_cast_t< U, details::types<Ts...> >{}( std::forward<U>(u) ))
{
return details::smart_cast_t< U, details::types<Ts...> >{}( std::forward<U>(u) );
}
现在,我们的想法是我们现在可以修改foo,如下所示:
void foo_impl(X);
void foo_impl(Y);
template<class A>
void foo(A&& a) {
foo_impl( smart_cast<X, Y>(std::forward<A>(a)) );
}
如果可能,foo 将 A 转换为 X,如果不能转换为 Y。
我们可以编写一个完整的系统,将foo 重载的描述传递给像types< types<X,Y> > 这样的包和foo 的重载集到一些魔术代码,它会输出一个调度程序,但是那将是过度工程。
live example
这使用了 C++11 特性。使用 C++14,我们可以在 smart_cast 中删除一些措辞。
设计非常简单。我们创建了一个 types 包来处理类型包(只是样板文件)。
然后我们的details::smart_cast_t 有一个备用基础专业化,它只是将我们的U 转换为U。如果我们可以将U 转换为第一种类型,我们就会这样做。否则,我们会在父类型上递归,可能会终止于基础特化。
我把它隐藏了,所以我们的公共函数很简单——它是smart_cast< type1, type2, type3, etc >( expression )。我们不必传递U 表达式的类型,因为我们推断它,然后将其传递到要完成的工作的细节中。
在运行时,这会简化为一个隐式强制转换:以上所有内容都是在编译时完成的。
唯一的缺点是这可能会导致某些编译器出现警告,因为我们使用隐式转换。将static_cast<T0> 添加到smart_cast_t 的第一个非基本特化中以避免这种情况。
我不必要地从true_type 和false_type 继承了smart_cast_t。这意味着smart_cast_t<U, types<Ts...>>::value 的值将告诉您U 是否转换为Ts... 中的任何一个,或者只是作为U 单独存在。
调用者负责右值与左值类别。如果转换失败,如果传递了一个右值,它将返回一个U 而不是U&&。回退 - 到 U - 我认为会生成更好的错误消息,但如果您希望 smart_cast<int, double>(std::string("hello")) 无法编译而不是返回 std::string,只需从 @987654357 的基本特化中删除 operator() @。
说起来,我也不适合smart_cast<int, double>("")。可能需要一些typename std::decay<U>::types 或其中的一些东西。