5

问题:

有没有办法从 C++ 中的专用模板函数调用“基本”模板函数,子类在覆盖它们时可以访问父类的虚拟方法版本的方式?(注意:我怀疑答案是否定的,但很想弄错)

上下文:

我经常发现自己专门研究模板函数只是因为特殊情况需要额外的预处理或后处理,而不是因为代码的“胆量”发生了变化。

举一个人为的例子:

通过继承,您可以执行以下操作:

struct base { 
    virtual void go() { printf("%p", this); }
};
struct foo : base { 
    virtual void go() { printf("this foo lives at "); base::go(); } 
};

...并调用 foo::go() 将打印“this foo living at <address>”

但是,使用模板:

template <typename T>
void go(T const &t) { printf("%p\n", &t); }

template <>
void go(foo const &f) { 
    printf("this foo lives at "); 
    ??? how to access "base" template ??? 
}

您可以通过分解出一堆小辅助函数并专门化它们而不是您真正关心的函数来以一种丑陋的方式解决这个问题:

template <typename T>
void _go_pre(T const &t) { /* do nothing */ }

template <typename T>
void _go_post(T const &t) { /* do nothing */ }

template <typename T>
void go(T const &t) { 
    _go_pre(t); /* just in case */
    printf("%p\n", &t); 
    _go_post(t); 
}

template<>
void _go_pre(foo const &t) { printf("this foo lives at "); }

...但这会使代码变得非常混乱,因为现在“基本”模板需要预测“子”特化可能覆盖它的所有方式,并且大多数类型将使用很少(如果有的话)这些钩子。混乱很快变得不可读和不可维护,因为这些钩子的原因在定义它们的时候是未知的,你必须测试使用/未使用钩子的不同组合。

所有这一切都与您在子类无法访问父类提供的原始版本的世界中使用虚拟方法覆盖时遇到的问题完全一样。

4

2 回答 2

3

直接是不可能的。但是,您可以使用更少(并且 IMO 不那么丑陋)的助手,如下所示:

template <typename T>
void base_go(T const &t) { printf("%p\n", &t); }

template <typename T>
void go(T const &t) { base_go(t); }

template<>
void go(foo const &t) { printf("this foo lives at "); base_go(t); }

作为替代方案,您可以将base_变体放入单独的命名空间,而不是给它们修改名称。

于 2013-06-03T13:39:14.837 回答
0

如果您的 foo 是普通类型,您可以简单地创建一个(非模板)函数重载并在内部调用模板化版本:

#include <iostream>

struct A {};
template<class T>
void f(T const&) {
    std::cout << "in f<T>(T const&)" << std::endl;
}

void f(A const& a) { 
    std::cout << "in f(A const&)" << std::endl;
    f<A>(a);
}

int main() {
    A a;
    f(a);
    return 0;
}
于 2013-06-03T14:50:37.153 回答