这可能非常愚蠢......
如果我有这样的模板类A,
template <class T1, class T2>
struct A
{
T1 a;
T2 b;
};
并且函数可以使用,
template <class T1, class T2>
void foo(A<T1, T2> *p)
{
}
现在我是A的子类,
struct B : A<int, int>
{
};
B b[100];
我无法推断出模板参数...
foo(b);
我必须这样写,
foo((B *)b);
或者像这样,
foo<int, int>(b);
现在还有更多, 我希望foo可以接受除A之外的其他东西并将它们视为A
template <class T>
struct A<T, void>
{
T a;
};
template <class T>
void foo(T *p)
{
foo((A<T, void> *)p);
}
现在除非我这样写,否则后来的foo被称为......
foo<int, int>(b);
这似乎可以做到
template <class T>
struct is_A_derived
{
typedef char (&yes)[1];
typedef char (&no)[2];
template <class T1, class T2>
static yes test(A<T1, T2> *);
static no test(...);
template <class T1, class T2>
static A<T1, T2> get_type(A<T1, T2> *);
static A<T, void> get_type(...);
template <class T1, class T2>
static A<T1, T2> base_type(A<T1, T2> *);
static int base_type(...); // guess or maybe hope this "int" is never used
static const bool value = sizeof(test((T *)0)) == sizeof(yes);
static const bool identical = value && sizeof(base_type((T *)0)) == sizeof(T);
typedef typename std::conditional<identical, decltype(get_type((T *)0)), A<T, void>>::type type;
};
答案 0 :(得分:1)
请注意,此代码将失败。您不能以多态方式使用C样式数组(无论模板如何)。
也就是说,您无法将数组 - B
视为 - A
数组。
如果你写p[1]
,你认为会怎么样?嗯,内部发生以下情况:
*(p + 1)
指针算术。现在,编译器将+ 1
进一步翻译为sizeof A
个字节的增量。但是您的数据结构不是sizeof A
大,而是sizeof B
!因此p[1]
将指向内存中的错误位置。
因此,编译器(完全是偶然!)通过禁止此调用来做正确的事情。
答案 1 :(得分:0)
在第一种情况下,实际上存在将B数组衰减到A *指针的危险,以防您在A *指针上发生指针运算。
令我惊讶的是它没有解决但可能是一个很好的安全功能,以防你计划在A数组上执行一个函数,这对于B数组不起作用。
您可以foo( &b[0] )
而不是投射或显式模板。
在后一种情况下,如果它与A模板上的函数同名,则现在使用T *上的函数foo使事情变得复杂。
一旦你添加了第二个foo,B上的调用确实会选择第二个foo,因为它现在变成了一个完美的匹配。使用聪明的SFINAE技术可以赋予子类更高的优先级,以查看它是否为A。一般来说,除非你真的需要,否则我会避免使用它。