当模板类未特化时,成员函数的特化模板的解决方案
Workaround for specialized template for member function, when template class is not specialized
我正在构建一个具有类似std接口的数据结构类,并为该数据结构实现不同的迭代器。
从概念上讲,我想做的是这样的:template <class DataT>
class DataStructure
{
protected:
DataT& Data;
public:
DataStructure(DataT& data) : Data(data) {}
class BaseIterator
{
public:
BaseIterator()
{
cout<<"BaseIterator"<<endl;
}
};
class DerrivedIterator1 : public BaseIterator
{
public:
DerrivedIterator1()
{
cout<<"DerrivedIterator1"<<endl;
}
};
class DerrivedIterator2 : public BaseIterator
{
public:
DerrivedIterator2()
{
cout<<"DerrivedIterator2"<<endl;
}
};
template<class IterT>
IterT Begin()
{
//none-specialized implementation. Possibly throw exception
}
template<>
DerrivedIterator1 Begin<DerrivedIterator1>()
{
//Find beginning for DerrivedIterator1
}
template<>
DerrivedIterator2 Begin<DerrivedIterator2>()
{
//Find beginning for DerrivedIterator1
}
};
但是这当然不能编译,因为c++不允许在非特化的模板容器中特化模板成员函数。
明显的解决方法当然是声明两个不同的函数:Begin_Iterator1和Begin_Iterator2,然后完成它。但是我正在寻找一个不改变界面的解决方案。
任何想法?
编辑:我忘了说这是一个HW赋值,所以boost甚至std都不是一个选项。
函数模板不能在c++中专门化,一点。
无论是否是模板的成员,都不允许对函数模板进行专门化。通常,当使用实参类型推断模板实参时,重载会执行相同的特化操作,因此函数的特化(以及在重载解析等方面相关的额外复杂性)被认为是不必要的。
然而,你没有任何参数来推断,将手动实例化模板。不,DataStructure::DerivedIterator1 i = dataStructure.Begin();
将不能在您编写代码时工作,因为类型推断,就像重载解析一样,只在参数上完成,而不是预期的返回值。你必须写:
DataStructure::DerivedIterator1 i = dataStructure.Begin<DataStructure::DerivedIterator1>();
和
相比没有任何好处DataStructure::DerivedIterator1 i = dataStructure.BeginIterator1();
然而,第一个表达式可以通过一些魔法来实现。首先,你必须定义BeginIterator1
和BeginIterator2
,然后你做一个临时的,以迟决定构造哪一个:
class DataStructure {
...
class BeginIteratorConstructor {
DataStructure &dataStructure;
public:
BeginIteratorConstructor(DataStructure &ds) : dataStructure(ds) {}
operator DerivedIterator1() { return dataStructure.BeginIterator1(); }
operator DerivedIterator2() { return dataStructure.BeginIterator2(); }
};
BeginIteratorConstructor Begin() { return BeginIteratorConstructor(*this); }
...
};
现在dataStructure.Begin()
将返回一个临时的东西,如果你将其转换为DerivedIterator1
,它将调用BeginIterator1
,或者当你将其转换为DerivedIterator2
时调用BeginIterator2
。如果将其传递给某个对象,而编译器无法决定将其强制转换给哪一个对象,则它将死,要么是因为有二义性重载,要么是因为BeginIteratorConstructor
实际上不是迭代器,因此必须显式强制转换。
(您应该小心地使尽可能多的BeginIteratorConstructor
私有,但我不确定编译器将允许您走多远,所以您必须尝试一下)
您可以使用标记系统,它将使您免于在类模板中使用部分专门化的函数:
struct base_iter_tag{};
struct der1_iter_tag{};
struct der2_iter_tag{};
template<class T>
struct iter_type;
template<>
struct iter_type<BaseIterator>{
typedef base_iter_tag tag;
};
template<>
struct iter_type<DerivedIterator1>{
typedef der1_iter_tag tag;
};
template<>
struct iter_type<DerivedIterator2>{
typedef der2_iter_tag tag;
};
template<class IterT>
IterT Begin(){
return DoBegin(typename iter_type<IterT>::tag());
}
BaseIterator DoBegin(base_iter_tag){
// ...
}
DerivedIterator1 DoBegin(der1_iter_tag){
// ...
}
DerivedIterator2 DoBegin(der2_iter_tag){
// ...
}
这基本上是标准库根据类别(例如forward_iterator_tag
, random_access_iterator_tag
等…)对iterator_traits<T>::iterator_category
和重载函数所做的。
- 运行同一解决方案的另一个项目的项目
- Project Euler问题4的错误解决方案
- 计算每个节点的树高,帮助我解释这个代码解决方案
- C++:Application.cpp中抛出了未解析的外部符号(解决方案在问题的末尾,供未来的读者参考)
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- sort() 方法 c++ 中的比较器函数.为大量数字获得不同的解决方案
- VS为我提供了对构造函数的另一个解决方案,但我想知道为什么我的工作不起作用
- 在这种情况下,有没有办法用单个解决方案替换两个仅在类型上不同的相似函数?
- 正在(在构造函数中)将其包含一个不良设计的指针传递,如果是的,则解决方案是什么
- 实例化函数的多个模板并在运行时选择的通用解决方案
- 任何解压缩向量以在C++中函数参数的解决方案
- VS2013 RC中函数模板的过载解决方案
- VC++在解决方案中从非/clr项目的函数调用/clr工程的函数
- 模板函数重载解决方案
- 这个解决方案对MSVC的双重检查锁定错误和函数静态有什么问题?
- 为std::function赋值抽象函数——为什么std::ref是一个解决方案
- 不允许void的部分函数专门化-替代解决方案
- 寻找c++成员函数覆盖(非虚拟)的解决方案
- 函数参数 -> 结构体成员的 void* 和常量 void* 的解决方案
- 当模板类未特化时,成员函数的特化模板的解决方案