hoc*_*chl 1 c++ templates overloading template-specialization c++03
我有一个类层次结构,可以使用它写入对象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;
}
Run Code Online (Sandbox Code Playgroud)
这会产生以下输出:
Shift& Shift::operator<<(const Base&)
Shift& Shift::operator<<(const U&) [with U = Derived]
Shift& Shift::operator<<(const U&) [with U = int]
Run Code Online (Sandbox Code Playgroud)
如果我取消注释该#if 0部分,它将更改为所需的输出:
Shift& Shift::operator<<(const Base&)
Shift& Shift::operator<<(const Derived&)
Shift& Shift::operator<<(const U&) [with U = int]
Run Code Online (Sandbox Code Playgroud)
我有很多派生类(实际上是一个完整的层次结构),直到现在我必须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;
}
};
Run Code Online (Sandbox Code Playgroud)
输出:
static void Helper<Base>::shift()
static void Helper<T>::shift() [with T = Derived]
static void Helper<T>::shift() [with T = int]
Run Code Online (Sandbox Code Playgroud)
但仍然调用基本模板,而不是Base专门化.
PPS:不幸的是,我目前仅限于C++03没有Boost.
在您当前的实现中,根据§13.3.3.1.4[over.ics.ref]/p1,首选模板化重载:
当引用类型的参数直接(8.5.3)绑定到参数表达式时,隐式转换序列是标识转换,除非参数表达式的类型是参数类型的派生类,在这种情况下隐式转换sequence是派生到基础的转换(13.3.3.1).
由于派生到基础转换被赋予转换等级,为了获得所需的输出,在过载解析期间,必须通过使用适当的条件(SFINAE)从具有可用功能的集合中排除具有身份转换等级的模板化版本enable_if:
#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;
}
Run Code Online (Sandbox Code Playgroud)
输出:
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&]
Run Code Online (Sandbox Code Playgroud)
在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;
}
Run Code Online (Sandbox Code Playgroud)