Я хочу реализовать шаблонную функцию, используя вложенные типы шаблонного класса.
Я только что прочитал Вот что лучше реализовать 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
это может быть использовано для вашего случая. Еще хуже: нет способа написать такую черту, просто используя простые определения типов, поскольку нет ничего особенного в том, чтобы определить тип внутри определенного класса — компилятор не может определить (и не заинтересован), является ли данный известный Тип имеет псевдоним для него где-то.
Но если ваши typedefs — это те, которые вы показываете в своем вопросе, у меня для вас хорошие новости: вам нужно ровно два operator<<
для этого:
boost::dynamic_bitset<>
, так как это BoolTable для любой Создание экземпляров MyClass.std::vector<T>
, так как это MsgTable для каждого соответствующего MyClass<T>
, Недостатком является то, что с этим operator<<
, вы сможете вывести любой std::vector<FooBar>
, даже если FooBar
совершенно не связано с любым использованием MyClass. Но это относится к любой другой возможной реализации надлежащего operator<<
s — если нет явного ограничения на параметр MSG, нет ограничения на создание FooBar std::vector<FooBar>
жизнеспособный MyClass<MSG>::MsgTable
,
Мой вывод на ваш вопрос: вы хотели иметь operator<<
для его удобного взгляда, так как он обычно используется для этих целей. В вашем случае вы можете предоставить его для MyClass<MSG>
объекты, но нет никакого способа сделать это только для внутренних typedefs.
Я бы реализовал это так:
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;
}
Я полагаю, вы что-то путаете. Типовое имя просто для того, чтобы иметь возможность отделить его от других параметров шаблона. Попробуйте переименовать его в
template <typename OS, typename MSG, typename MSGTable>
OS& operator << (OS& os, const MSGTable& table) const{}
а затем использовать его как объект.
Увидеть Вот.