gpt4 book ai didi

c++ - 这种使用模板的类层次结构的函数重载方式安全吗?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:36:00 25 4
gpt4 key购买 nike

好的,这有点复杂,所以请耐心等待。 :)

我们有这个简单的类层次结构:

class A {};
class DA : public A {};
class DDA : public DA {};

我们在这些类上运行了以下函数:

void f(A x) {
std::cout << "f A" << std::endl;
}
void f(DA x) {
std::cout << "f DA" << std::endl;
}
void f(DDA x) {
std::cout << "f DDA" << std::endl;
}

现在我们想添加另一个函数,以稍微不同的方式处理 DA。

(1) 第一次尝试可能是这样的:

void g(A t) {
std::cout << "generic treatment of A" << std::endl;
std::cout << "called from g: ";
f(t);
}
void g(DA t) {
std::cout << "special treatment of DA" << std::endl;
std::cout << "called from g: ";
f(t);
}

但是用每个类的对象调用它显然没有达到预期的效果。

调用:

  A a; DA b; DDA c;
g(a); g(b); g(c)

结果:

generic treatment of A
called from g: f A
special treatment of DA
called from g: f DA
special treatment of DA
called from g: f DA //PROBLEM: g forgot that this DA was actually a DDA

(2) 所以我们可能会尝试使用模板:

template<typename T>
void h(T t) {
std::cout << "generic treatment of A" << std::endl;
std::cout << "called from h: ";
f(t);
}

template<>
void h<>(DA t) {
std::cout << "special treatment of DA" << std::endl;
std::cout << "called from h: ";
f(t);
}

结果是:

generic treatment of A
called from h: f A
special treatment of DA
called from h: f DA
generic treatment of A //PROBLEM: template specialization is not used
called from h: f DDA

好吧,我们不使用模板特化而是为特殊情况定义一个非模板函数怎么样? (Article 关于非常令人困惑的事情。)事实证明它的行为方式完全相同,因为根据文章“一等公民”的非模板函数似乎丢失了,因为类型转换是必要的用它。如果它被使用,那么我们将回到第一个解决方案(我假设)并且它会忘记 DDA 的类型。

(3) 现在我在工作中遇到这段代码,对我来说似乎很奇特:

template<typename T>
void i(T t, void* magic) {
std::cout << "generic treatment of A" << std::endl;
std::cout << "called from i: ";
f(t);
}

template<typename T>
void i(T t, DA* magic) {
std::cout << "special treatment of DA" << std::endl;
std::cout << "called from i: ";
f(t);
}

但它似乎完全符合我的要求:

generic treatment of A
called from i: f A
special treatment of DA
called from i: f DA
special treatment of DA
called from i: f DDA

尽管它需要以一种奇怪的方式被调用: 我(一个,&一个);我(b,&b);我(c, &c);

现在我有几个问题:

  1. 这到底为什么行得通?
  2. 你认为这是个好主意吗?哪里可能存在陷阱?
  3. 您建议采用哪些其他方式进行此类特化?
  4. (类型转换如何适应模板偏序等等的疯狂......)

我希望这是相当清楚的。 :)

最佳答案

函数模板重载

template<typename T>
void i(T t, DA* magic) {

仅当参数 magic 可转换为类型 DA * 时才可用。显然 &b&c 都是这种情况,因为派生指针可以转换为基指针。 void * 函数模板重载始终可用,但 DA * 优于 void *,根据 §13.3.3.2:4:

13.3.3.2 Ranking implicit conversion sequences [over.ics.rank]

[...]

4 Standard conversion sequences are ordered by their ranks: an Exact Match is a better conversion than a Promotion, which is a better conversion than a Conversion. Two conversion sequences with the same rank are indistinguishable unless one of the following rules applies:

[...]

— If class B is derived directly or indirectly from class A, conversion of B* to A* is better than conversion of B* to void*, and conversion of A* to void* is better than conversion of B* to void*.

正如您所指出的,这是一个非常可行的方案;将魔法包装在另一个模板函数中会更有意义,该函数负责使用 (a, &a) 调用 i:

template<typename T>
void j(T t) {
i(t, &t);
}

安全方面,还好;如果 DA * 重载丢失,则 void * 重载将被静默选择;由您决定这是否可取。

作为替代方案,您可以使用 std::enable_if 在模板之间进行选择:

template<typename T>
typename std::enable_if<!std::is_base_of<DA, T>::value>::type g(T t) {
std::cout << "generic treatment of A" << std::endl;
f(t);
}
template<typename T>
typename std::enable_if<std::is_base_of<DA, T>::value>::type g(T t) {
std::cout << "special treatment of DA" << std::endl;
f(t);
}

关于c++ - 这种使用模板的类层次结构的函数重载方式安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11650868/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com