调用模板函数而不是基类型的函数
Template function gets called instead of function of base type
我有一个可以使用operator<<
写入对象的类层次结构。该示例如下所示:
#include <iostream>
struct Base
{
};
struct Derived : public Base
{
};
struct Shift
{
template< typename U >
Shift& operator<<(const U&)
{
std::cerr << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
Shift& operator<<(const Base&)
{
std::cerr << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
#if 0
Shift& operator<<(const Derived&)
{
std::cerr << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
#endif
};
int main()
{
Shift sh;
Base bas;
Derived der;
int u32 = 0;
sh << bas;
sh << der;
sh << u32;
}
这将生成以下输出:
Shift& Shift::operator<<(const Base&)
Shift& Shift::operator<<(const U&) [with U = Derived]
Shift& Shift::operator<<(const U&) [with U = int]
如果我取消注释#if 0
部分,它将更改为所需的输出:
Shift& Shift::operator<<(const Base&)
Shift& Shift::operator<<(const Derived&)
Shift& Shift::operator<<(const U&) [with U = int]
我有很多派生类(实际上是整个层次结构(,直到现在我必须为所有这些类型编写单独的operator<<
定义。我想要的是一个解决方案,其中为派生自Base
的所有类型调用基类型的运算符。这可能吗?
PS:我尝试了几种解决方案,例如编写一个帮助程序类:
struct Base
{
};
struct Derived : public Base
{
};
template< typename T >
struct Helper
{
static void shift()
{
std::cerr << __PRETTY_FUNCTION__ << std::endl;
}
};
template< >
struct Helper< Base >
{
static void shift()
{
std::cerr << __PRETTY_FUNCTION__ << std::endl;
}
};
struct Shift
{
template< typename U >
Shift& operator<<(const U& value)
{
Helper< U >::shift();
return *this;
}
};
输出:
static void Helper<Base>::shift()
static void Helper<T>::shift() [with T = Derived]
static void Helper<T>::shift() [with T = int]
但仍然调用基本模板,而不是Base
专用化。
P.P.S.:不幸的是,我目前仅限于没有Boost
的C++03
。
在当前的实现中,模板化重载是首选,如 §13.3.3.1.4 [over.ics.ref]/p1:
当引用类型的参数直接绑定 (8.5.3( 到参数表达式时,隐式转换序列是标识转换,除非参数表达式的类型是参数类型的派生类,在这种情况下,隐式转换序列是派生到基的转换 (13.3.3.1(。
由于派生到基数转换被赋予转换等级,因此为了实现所需的输出,必须在重载解析期间使用具有适当条件的enable_if
(SFINAE( 从可行函数集中排除具有标识转换等级的模板化版本:
#include <type_traits>
//...
template <typename U>
auto operator<<(const U&)
-> typename std::enable_if<!std::is_base_of<Base, U>{}, Shift&>::type
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
Shift& operator<<(const Base&)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
输出:
Shift& Shift::operator<<(const Base&)
Shift& Shift::operator<<(const Base&)
typename std::enable_if<(! std::is_base_of<Base, U>{}), Shift&>::type Shift::operator<<(const U&) [with U = int; typename std::enable_if<(! std::is_base_of<Base, U>{}), Shift&>::type = Shift&]
在 c++03 中,实现的可读性较差:
template <bool B, typename T = void>
struct enable_if { typedef T type; };
template <typename T>
struct enable_if<false, T> {};
template <typename Base, typename Derived>
struct is_base_of
{
typedef char (&yes)[1];
typedef char (&no)[2];
static yes test(Base*);
static no test(...);
static const bool value = sizeof(test((Derived*)0)) == sizeof(yes);
};
template <typename Base, typename Derived>
const bool is_base_of<Base, Derived>::value;
//...
template <typename U>
typename enable_if<!is_base_of<Base, U>::value, Shift&>::type operator<<(const U&)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
Shift& operator<<(const Base&)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
相关文章:
- 基类中的函数名称解析
- 如何通过派生类函数更改基类中的向量
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如果基类包含双指针成员,则派生类的构造函数
- C++ 继承:将子类传递给需要基类的函数并获取子类行为
- 继承和友元函数,从基类访问受保护的成员
- 使用子类覆盖基类中定义的函数
- 如何基于模板化类的基类专门化成员函数
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 使用基类指针调用基类的值构造函数的语法是什么?
- C++重载函数,一个采用基类的参数,另一个采用派生类的参数
- 如何在基类指针向量的元素上应用重载的多态函数
- 如何在不使用指针的情况下将派生类的对象作为参数传递给基类中的函数?
- 被覆盖的函数不会反映在基类中,这是正常行为吗?
- 在初始化列表之外手动调用基类的构造函数
- 重写打印函数而不是覆盖基类
- C++17 使用驱动类常量作为基类构造函数的参数来初始化基类构造函数
- C++虚拟函数:基类函数是调用的,而不是派生的
- 虚拟函数-基类指针