您可以通过使用约束模板化构造函数(将在转换中使用)来实现此目的std::enable_if
和一些模板元编程:
template <template <class> typename BaseTemplate,
typename From,
typename To,
typename Enable = void>
struct may_convert
: public std::false_type {};
template <template <class> typename BaseTemplate,
typename T>
struct may_convert<BaseTemplate, BaseTemplate<T>, BaseTemplate<T>, void>
: public std::true_type {};
template <template <class> typename BaseTemplate,
typename T,
typename U>
struct may_convert<BaseTemplate, BaseTemplate<T>, BaseTemplate<U>,
typename std::enable_if<!std::is_same<T, U>::value>::type>
: public may_convert<BaseTemplate, T, BaseTemplate<U>> {};
may_convert
将走上模板From
模板参数直到它等于To
(在这种情况下它继承自std::true_type
, i.e. may_convert<...>::value
is true
),或者直到模板用完(在这种情况下may_convert<...>::value
is false
).
现在,剩下的就是适当地限制你的构造函数:
template <typename Convertible>
class A {
public:
A() {}
template <typename T,
typename = typename std::enable_if<
may_convert<A, T, A<Convertible>>::value>::type>
A(const T&) {}
};
这样,构造函数仅在以下情况下存在:may_convert<...>::value
is true
。否则,转换将会失败。
Examples
以下是如何操作的示例may_convert
在您的示例中有效(从D = A<A<A<int>>>
to B = A<int>
):
构造函数仅存在于may_convert<A, D, B>::value
is true
may_convert<A, D, B>
匹配最后一个专业化(因为D = A<C>
and B = A<int>
,参数推导为T = C
and U = int
)并继承自may_convert<A, C, B>
may_convert<A, C, B>
再次匹配最后一个专业化(T = B
, U = int
)并继承自may_convert<A, B, B>
这次,这两种类型是相等的,因此第一个特化匹配,并且整个事物继承自std::true_type
,启用构造函数。
另一方面,想象一个using E = A<double>
不应该转换为B
:
仅在以下情况下才会启用构造函数may_convert<A, E, B>::value
is true
may_convert<A, E, B>
匹配最后一个专业化,并继承自may_convert<A, double, B>
Because double
不是一个A<...>
,没有一个专业化匹配,所以我们回退到默认情况,它继承自std::false_type
.
所以,may_convert<A, E, B>::value
is false
,并且转换失败。