问题
我有一系列约 10 个模板类 A、B、C、D...
我想启用从一个类到系列中以前的类的转换:
- D -> C、B 或 A
- C -> B,或 A
- B -> A
如何在不使用公共(public)继承的情况下做到这一点?
测试 1(公共(public)继承)
- 我不想继承公共(public)方法。
测试 2(定义 1 + 2 + ... n 转换运算符):
- 为第n个模板类定义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 层将一个层转换为另一个容器。 (例如,带有用于通过键 inode 和跟踪节点交换的散列层。)
用户可以通过多种方式堆叠层来创建对象S。
我希望将一层的节点转换为前一层的节点。
这是可能的,因为节点内容的指针/索引是相同的。
最佳答案
您可以通过使用 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
)并继承自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
是false
, 转换失败。
关于c++ - 没有公共(public)继承的类之间的链式转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50307311/