问题
我有一系列~10个模板类A,B,C,D,......
我想启用从类到系列中以前的类的转换:
如何在不使用公共继承的情况下实现这一目标?
测试1 (公共继承)
测试2 (定义1 + 2 + ... n转换运算符):
测试3 (每班1个转换运算符):
例如,它允许从D转换为C,但不能从D转换为B.
测试(也在godbolt.org):
template <typename Convertible>
class A {
public:
operator Convertible() { return Convertible(); }
};
using B = A<int>;
using C = A<B>;
using D = A<C>;
int main() {
D d;
auto b = B(d);
return 0;
}
编译错误:
error: no matching function for call to ‘A<int>::A(D&)’
auto b = B(d);
^
实际使用案例
A,B,C,D ......是由对象S层创建的每个节点(代理)。
类型1层定义图形节点的内存组织 (指针/阵列)。
第2层将图层转换为另一个容器。 (例如,带有散列的层,用于按键索引节点和跟踪节点的交换。)
用户可以通过多种方式堆叠图层来创建对象S.
我希望一层的节点转换为先前层的节点。
这是可能的,因为指向节点内容的/ index的指针是相同的。
答案 0 :(得分:2)
您可以通过使用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
,即may_convert<...>::value
} {是true
),或者在模板用完之前(在这种情况下may_convert<...>::value
是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
为true
时,构造函数才存在。否则,转换将失败。
以下是may_convert
在您的示例中的工作原理示例(从D = A<A<A<int>>>
转换为B = A<int>
):
只有当may_convert<A, D, B>::value
为true
may_convert<A, D, B>
匹配上一个专门化(因为D = A<C>
和B = A<int>
,参数推断为T = C
和U = int
)并且继承自{ {1}}
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
true
与上一次专精化相匹配,并继承自may_convert<A, E, B>
由于may_convert<A, double, B>
不是double
,因此没有一个专业化匹配,因此我们回到默认情况,它继承自A<...>
。
因此,std::false_type
为may_convert<A, E, B>::value
,转换失败。