我想从包含模板化成员函数的类派生。在派生类中,我想为成员函数添加一些更多的特化。但是,如何使父类中已定义的方法可见。通常我必须使用using
,但我找不到模板化方法的正确语法。我怎么说我想在派生类中定义更专业的方法而不覆盖基类的非专用方法。
在我们写2017年的时候,欢迎任何现代的c ++方言。
#include <iostream>
class MyType1{};
class MyType2{};
class A
{
public:
template <typename T>
void Do() {std::cout << "Default" << std::endl; }
};
template<>
void A::Do<MyType1>() { std::cout << "For MyType1" << std::endl; }
class B : public A
{
public:
using A::Do; ??? how to do this for templated members?
// how to make it possible to write more specializations without
// defining a new "default" one?
template <typename T>
void Do() {std::cout << "Default of B" << std::endl; }
};
template<>
void B::Do<MyType2> (){ std::cout << "For MyType2" << std::endl; }
int main()
{
A a;
a.Do<int>(); // should give "Default"
a.Do<MyType1>(); // should give "For MyType1"
a.Do<MyType2>(); // should give "Default"
std::cout << "-----------" << std::endl;
B b;
b.Do<int>(); // should give "Default"
b.Do<MyType1>(); // should give "For MyType1"
b.Do<MyType2>(); // should give "For MyType2"
}
答案 0 :(得分:1)
当好的旧标签发送将帮助我们解决时,让我们不要全部陷入C ++ 17:
namespace detail{
template<class...>
struct tag{}; // for dispatch to overloads below
}
class A
{
public:
template <typename T>
void Do() {
DoHelp(detail::tag<T>{});
}
protected:
template<class... U>
void DoHelp(detail::tag<U...>)
{
std::cout << "Default" << std::endl;
}
void DoHelp(detail::tag<MyType1>)
{
std::cout << "For MyType1" << std::endl;
}
};
class B : public A
{
public:
template <typename T>
void Do() {
DoHelp(detail::tag<T>{});
}
protected:
using A::DoHelp;
void DoHelp(detail::tag<MyType2>){
std::cout << "For MyType2" << std::endl;
}
};
输出:
Default
For MyType1
Default
-----------
Default
For MyType1
For MyType2
您已经看到using
语句成功引入了模板化名称,但与继承构造函数不同,它实际上并不会创建这些成员函数,这会强制您为Do
专门化A
这不是你想要的。
因此,我们为A
中我们想要专门化的类型定义重载,并为我们想要在B
中专门化的类型单独定义重载。不幸的是,我们必须隐藏A
Do
B
函数与我们自己的A
函数,因为类B
无法调度到B的重载(但A
可以调度到using
{1}}。DoHelp
的{{1}}语句是B
可以看到A
的重载。)
如您所见,tag
只是一个空模板struct
。我们使用它来区分其他相同的函数(DoHelp
)。因为我们不使用参数,优化编译器实际上不会构造对象,所以我们不应该看到任何开销。如果我们这样做,它将只有1个字节。
答案 1 :(得分:-1)
通过在B类中编写Do方法,您实际上是在添加一个新的模板成员函数,该函数隐藏A :: Do而不添加A :: Do特化。也没有必要使用A :: Do;&#34;言。