使用模板类的嵌套类型作为模板参数
using nested-types of a template-class as template parameter
我想使用模板类的嵌套类型来实现一个模板函数。
我刚刚在这里读到,最好将operator <<
实现为非成员和非朋友函数。因此,我决定将函数toStream()
和tableToStream()
移到MyClass
:之外
template <typename T>
class MyClass
{
public:
typedef boost::dynamic_bitset<> BoolTable;
typedef std::vector<T> MsgTable;
private:
BoolTable b_;
MsgTable m_;
public:
const BoolTable& getB() const { return b_; }
const MsgTable & getM() const { return m_; }
std::ostream& toStream (std::ostream& os) const
{
os <<"Bool: "; tableToStream (os, getB()); os <<'n';
os <<"Msg:"; tableToStream (os, getM()); os <<'n';
return os;
}
template <typename TABLE>
std::ostream& tableToStream (std::ostream& os, const TABLE& table) const
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
};
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T> mc)
{
return mc.toStream(os);
}
很容易将MyClass::toStream()
转换为operator <<
非成员非好友函数:
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc)
{
os <<"Bool: "; mc.tableToStream (os, mc.getB()); os <<'n';
os <<"Msg:"; mc.tableToStream (os, mc.getM()); os <<'n';
return os;
}
但我想只使用operator <<
,而不是调用MyClass::tableToStream()
:
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc)
{
os <<"Bool: "<< mc.getB() <<'n';
os <<"Msg:" << mc.getM() <<'n';
return os;
}
对于函数MyClass::tableToStream()
,我可以使用以下实现,但这可能会扰乱流输出,因为函数太通用(任何类型都可以是TABLE
)。
template <typename TABLE>
std::ostream& operator << (std::ostream& os, const TABLE& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
因此,我想限制为MyClass
的嵌套类型。以下是我尝试将MyClass::tableToStream()
转换为标准的operator <<
非成员和非朋友函数的一个例子:
template <typename T, typename MyClass<T>::TABLE>
std::ostream& operator << (std::ostream& os, const TABLE& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
但误差是关于typename MyClass<T>::TABLE
。
由于您已经澄清了很多问题,我的第一个答案不再适用,我将删除编辑它,为您提供更适合的内容:
更新答案:您希望将模板约束为仅接受在MyClass模板内进行类型定义的类型。这些约束通常通过应用SFINAE来实现,尤其是通过std::enable_if
(或者boost::enable_if
,如果您的库缺少C++11的支持)。遗憾的是,没有像is_typedeffed_inside
这样的特征可以用于您的案例。更糟糕的是:没有办法只使用普通的typedef来编写这样的特性,因为在给定的类中进行typedef没有什么特别的——编译器没有办法确定(也不感兴趣)给定的已知类型是否在某个地方有别名。
但是,如果你的typedef只是你在问题中显示的类型,我有个好消息要告诉你:你需要两个operator<<
:
- 一个用于
boost::dynamic_bitset<>
,因为这是任何MyClass实例化的BoolTable - 另一个是模板化的,用于
std::vector<T>
,因为这是每个相应MyClass<T>
的MsgTable
缺点是,使用这个模板化的operator<<
,您将能够输出任何std::vector<FooBar>
,即使FooBar
与MyClass的任何使用完全无关。但这适用于正确的operator<<
的任何其他可能的实现——如果对MSG参数没有明确的限制,那么FooBar就不会限制std::vector<FooBar>
成为可行的MyClass<MSG>::MsgTable
。
我对你的问题的结论是:你想要operator<<
,因为它看起来很方便,因为它通常用于软用途。在您的情况下,您可以为MyClass<MSG>
对象提供它,但无法仅为内部typedef提供它。
我会这样实现:
template <class MSG>
class MyClass {
/* ... */
public:
// instead of declaring op<< a friend, redirect to a method that has
// natural access to private members
std::ostream& printToStream(std::ostream& os) const
{
os << "Bool: ";
tableToStream (getB(), os);
os <<"nMsg:";
tableToStream (getM(), os);
return os <<'n';
}
private:
// make this one private so nobody can misuse it to print unrelated stuff
template <class Table>
static void tableToStream(Table const& table, std::ostream& os)
{
std::copy(begin(table), end(table), ostream_iterator(os, ", "));
}
};
template <typename MSG>
std::ostream& operator << (std::ostream& os, const MyClass<MSG>& mc)
{
return mc.printToStream(os);
}
您原来的类很好。的确,如果您希望有一个operator <<
来写入流,那么它应该是一个非成员非好友函数,就像您所拥有的一样,但该函数没有理由不能调用公共成员函数来完成这项工作。
我终于找到了这个类似的问题
在我的情况下,解决方案是:
template <typename T>
std::ostream& operator << (std::ostream& os,
typename MyClass<T>::TABLE const& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
更新:正如@ArneMertz所指出的,上述函数不起作用
以下是我测试过的完整代码:
#include <ostream>
#include <boost/dynamic_bitset.hpp>
template <typename T>
class MyClass
{
public:
typedef boost::dynamic_bitset<> BoolTable;
typedef std::vector<T> MsgTable;
BoolTable b_;
MsgTable m_;
const BoolTable& getB() const { return b_; }
const MsgTable & getM() const { return m_; }
};
template <typename T>
std::ostream& operator << (std::ostream& os,
typename MyClass<T>::TABLE const& table)
{
for (int i=0; i < table.size(); ++i)
os << table[i] <<',';
return os;
}
template <typename T>
std::ostream& operator << (std::ostream& os, const MyClass<T>& mc)
{
os <<"Bool: "<< mc.getB() <<'n'; // <-- this line is OK because it
os <<"Msg: "<< mc.getM() <<'n'; //uses boost operator<<
return os;
}
和main
功能:
#include <iostream>
int main()
{
MyClass<int> var;
var.b_.push_back(true);
var.b_.push_back(false);
var.b_.push_back(true);
var.m_.push_back(23);
var.m_.push_back(24);
var.m_.push_back(25);
std::cout << var;
}
我相信你混淆了一些东西。typename只是为了能够将它与其他模板参数分开。尝试将其重命名为
template <typename OS, typename MSG, typename MSGTable>
OS& operator << (OS& os, const MSGTable& table) const{}
然后像使用对象一样使用它。
请参见此处。
- CRTP:为什么获得嵌套类型和派生类的嵌套方法有区别
- 为什么在VS2015中模板相关的嵌套类型名称中不需要typename关键字?
- 为什么嵌套类型的基类不需要"typename"?
- 如何在C++中的另一个模板函数中使用属于模板化类的嵌套类型?
- 保持嵌套类型的挥发性
- 具有嵌套类型的类的概念
- 将嵌套类型的类分开为标题和源
- 如何解决C++嵌套类型的循环依赖关系
- 在 C++11 中,从私有嵌套类型继承是否合法?
- C++ 递归嵌套类型和名称注入
- 如何定义一个模板类函数,该函数在类外的签名中具有嵌套类型的模板参数
- 访问模板参数T的嵌套类型,即使T是指针
- 为什么reverse_iterator双重定义其嵌套类型
- 嵌套类型:结构与类
- 如何对嵌套类型执行部分模板专用化
- 将类型的嵌套类型引用为类模板的参数的问题
- 嵌套类型作为基类的模板参数
- 我们是否需要在嵌套类型的成员参数前面加上"::"?
- 是否可以基于模板类型参数的嵌套类型定义来专门化模板定义
- 使用模板类的嵌套类型作为模板参数