Есть такая проблема, не могу перегрузить оператор << в такой ситуации:
template <typename T> class C
{
};
template <template <class> class T> class A
{
public:
class B
{
int c;
};
C<A> c;
B b;
void f()
{
std::ostringstream s;
s << b;
}
};
имеется ввиду оператор для A::B. Пытаюсь написать так:
Компилятор (gcc 4.4.1) не находит подходящей функции для операции s << b. Причем описанной выше функции нет в кандидатах.
Как в таком случае можно перегрузить operator<< ?
29.12.09 14:04: Перенесено модератором из 'C/C++. Прикладные вопросы' — Кодт
Здравствуйте, Аноним, Вы писали:
А>Всем доброго времени суток.
А>Есть такая проблема, не могу перегрузить оператор << в такой ситуации:
... skiped ...
А>имеется ввиду оператор для A::B. Пытаюсь написать так:
... skiped ...
А>Компилятор (gcc 4.4.1) не находит подходящей функции для операции s << b. Причем описанной выше функции нет в кандидатах. А>Как в таком случае можно перегрузить operator<< ?
Как исправить в данном случае operator<< — затрудняюсь сказать. А нельзя ли поправить f()? Если вынести описание этого метода за класс и написать после описания шаблонного operator<< вот таким образом:
template< template<class> class T>
void A<T>::f()
{
operator<< <T>(std::cout,b);
}
Здравствуйте, Аноним, Вы писали:
А>Компилятор (gcc 4.4.1) не находит подходящей функции для операции s << b. Причем описанной выше функции нет в кандидатах. А>Как в таком случае можно перегрузить operator<< ?
Может так прокатит...
template <template <class> class T> class A
{
public:
class B
{
int c;
friend std::ostream& operator<<(std::ostream& s, B const& v)
{
return s << "";
}
};
};
. Template Deduction не работает на вложенные типы если обращение к ним пришлось писать с ключём typename. Соответственно всё что к ним должно приводится должно быть написанно там где непосредственно видино сам вложенный тип/typedef.
Здравствуйте, Аноним, Вы писали:
А>Всем доброго времени суток.
А>Есть такая проблема, не могу перегрузить оператор << в такой ситуации: А>
А>template <typename T> class C
А>{
А>};
А>template <template <class> class T> class A
А>{
А> public:
А> class B
А> {
А> int c;
А> };
А> C<A> c;
А> B b;
А> void f()
А> {
А> std::ostringstream s;
А> s << b;
А> }
А>};
А>
А>Как в таком случае можно перегрузить operator<< ?
Вынести класс B наружу и не париться. Вложенность классов без веских на то оснований — порочная практика.
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: operator<< дла класса вложенного в шаблонный
Здравствуйте, remark, Вы писали:
R>Здравствуйте, Аноним, Вы писали:
А>>Компилятор (gcc 4.4.1) не находит подходящей функции для операции s << b. Причем описанной выше функции нет в кандидатах. А>>Как в таком случае можно перегрузить operator<< ?
R>Может так прокатит...
R>
R>template <template <class> class T> class A
R>{
R> public:
R> class B
R> {
R> int c;
R> friend std::ostream& operator<<(std::ostream& s, B const& v)
R> {
R> return s << "";
R> }
R> };
R>};
R>
R>
Гм, занятный обходной маневр получается: в 14.8.2.4/9 перечислены формы параметров шаблонных функций, которые должен уметь выводить компилятор:
T
cv-list T
T*
T&
T[integer-constant]
template-name<T> (where template-name refers to a class template)
type(*)(T)
T(*)()
T(*)(T)
T type::*
type T::*
T T::*
T (type::*)()
type (T::*)()
type (type::*)(T)
type (T::*)(T)
T (type::*)(T)
T (T::*)()
T (T::*)(T)
type[i]
template-name<i> (where template-name refers to a class template)
TT<T>
TT<i>
TT<>
А с помощю предложенной техники мы этот список как бы расширяем еще одной формой:
T::type
Где type — имя вложенного типа, определенного внутри T (не typedef). Т.е. можно-таки решать уравнения по выведению обрамляющего типа!
--
Справедливость выше закона. А человечность выше справедливости.
Re[2]: operator<< дла класса вложенного в шаблонный
Здравствуйте, remark, Вы писали:
R>Может так прокатит...
R>
R>template <template <class> class T> class A
R>{
R> public:
R> class B
R> {
R> int c;
R> friend std::ostream& operator<<(std::ostream& s, B const& v)
R> {
R> return s << "";
R> }
R> };
R>};
R>
R>
Хм... Занятная конструкция. Только я не очень понимаю чем вообще является подобного рода функция.
если написать например так:
class A
{
public:
friend void f()
{
}
};
То функцию f() мне не удалось ниоткуда вызвать. Т.е. это может делать только компилятор (в применении к operator<<)?
Что это вообще такое? Как, например, будет выглядеть, тип указателя на такую функцию, если он вообще возможен?
Re[3]: operator<< дла класса вложенного в шаблонный
Здравствуйте, pzhy, Вы писали:
P>Хм... Занятная конструкция. Только я не очень понимаю чем вообще является подобного рода функция. P>если написать например так:
P>
rg45:
R>Гм, занятный обходной маневр получается: в 14.8.2.4/9 перечислены формы параметров шаблонных функций, которые должен уметь выводить компилятор:
R>А с помощю предложенной техники мы этот список как бы расширяем еще одной формой: R>
R>T::type
R>
R>Где type — имя вложенного типа, определенного внутри T (не typedef). Т.е. можно-таки решать уравнения по выведению обрамляющего типа!
Здесь нет вывода типа, т.к. определение
friend std::ostream& operator<<(std::ostream& s, B const& v)
{
return s << "";
}
с каждым инстанцированием шаблона A порождает определение обычной функции (не шаблона).
Re[3]: operator<< дла класса вложенного в шаблонный
Это потому, что friend declaration вводит в пространство имён функцию, не видимую при unqualified name lookup и qualified name lookup. В данном случае т.к. у функции нет никаких параметров, то очевидно, что и через argument-dependent name lookup она искаться не будет. Единственный способ сделать её видимой — это добавить обычное объявление:
#include <iostream>
class A
{
public:
friend void f()
{
std::cout << "f()" << std::endl;
}
};
int main()
{
void f(); // <--
f();
}
В остальном это обычная свободная функция.
Re[4]: operator<< дла класса вложенного в шаблонный
Здравствуйте, rg45, Вы писали:
R>Здравствуйте, Николай Ивченков, Вы писали:
НИ>>с каждым инстанцированием шаблона A порождает определение обычной функции (не шаблона).
R>Это понятно, но, тем не менее, снаружи, с точки зрения использующего кода очень похоже на то, как будто выполняется выведение типа.
Сейчас я попытаюсь оформить свою мысль более разборчиво.
Если у нас есть следующее определение шаблонного класса:
template <typename T>
struct A
{
struct Inner { T value; };
};
и мы хотим поиметь свободную функцию f, которую можно будет вызывать так:
A<int>::Inner i = { 123 };
A<double>::Inner d = { 1.23 };
A<std::string>::Inner s = { "Hello, World !!!" };
f(i);
f(d);
f(s);
то нам прийдется для каждого типа, которым мы параметризуем шаблонный класс A, завести для f отдельную перегрузку:
мы сразу же потеряем возможность автовыведения типов шаблонной функции f. Т.к. согласно 14.8.2.4/9 форма A<T>::Inner не подлежит автовыведению. Т.е. вызовы шаблонной функции f будут возможны только при явной спецификации шаблонного параметра:
f<int>(i);
f<double>(d);
f<std::string>(s);
Если же мы воспользуемся техникой, предложенной remark-ом, то мы и избавимся от необходимости определять отдельную перегрузку f для каждого типа в отдельности, и при этом вызовы f не потребуют дополнительной спецификации шаблонного параметра:
#include <iostream>
#include <string>
template <typename T>
struct A
{
struct Inner { T value; };
friend void f(const Inner& inner) { std::cout << inner.value << std::endl; }
};
int main()
{
A<int>::Inner i = { 123 };
A<double>::Inner d = { 1.23 };
A<std::string>::Inner s = { "Hello, World !!!" };
f(i);
f(d);
f(s);
}
Т.е. суммарный эффект получаем такой, как если бы компилятор умел выводить обрамляющий тип по вложенному.
--
Справедливость выше закона. А человечность выше справедливости.
Re[3]: operator<< дла класса вложенного в шаблонный