CRTP становится намного менее любопытным, если Вы полагаете, что тип подкласса, который передается суперклассу, только необходим во время расширения метода. Таким образом все типы определяются. Вам просто нужен шаблон для импорта символьного типа подкласса в суперкласс, но это - просто предописание - как все формальные шаблонные типы параметрического усилителя по определению - насколько суперкласс затронут.
Мы используем в несколько измененной форме, передавая подкласс в, черты вводят структуру к суперклассу для позволения суперклассу к эхо-сигналам производного типа. Приложение является библиотекой для геометрического исчисления (точки, векторы, строки, поля), где вся универсальная функциональность реализована в суперклассе, и подкласс просто определяет определенный тип: CFltPoint наследовался TGenPoint. Также CFltPoint существовал перед TGenPoint, таким образом разделяя на подклассы был естественный способ осуществить рефакторинг это.
Вы не можете исправить эту функцию. Ничто в спецификации не требует, чтобы компилятор оценивал вызов функции в выражении в каком-либо определенном порядке относительно какого-либо несвязанного оператора в том же выражении. Таким образом, без изменения вызывающего кода вы не можете заставить MyPrint ()
выполнить оценку после std :: cout << "Value:"
Для выражений, состоящих из нескольких последовательных операторов <<, так что это будет работать. Суть оператора <<, возвращающего поток, заключается в том, что когда операторы связаны в цепочку, LHS каждого из них определяется вычислением оператора слева от него.
Вы не можете добиться того же с бесплатными вызовами функций, потому что они нет LHS. MyPrint ()
возвращает объект, равный std :: cout
, как и std :: cout << "Value:"
, поэтому вы фактически выполняете std :: cout << std :: cout
, который печатает это шестнадцатеричное значение.
Поскольку желаемый результат:
Value: 12
"правильным" является переопределение оператора <<. Это часто означает, что вам нужно либо сделать его другом, либо сделать следующее:
class WhateverItIsYouReallyWantToPrint {
public:
void print(ostream &out) const {
// do whatever
}
};
ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
obj.print(out);
}
Если переопределение operator <<
для вашего класса не подходит, например, потому что существует несколько форматов, которые вы можете захотеть print, и вы хотите написать отдельную функцию для каждой из них, тогда вам следует либо отказаться от идеи объединения операторов и просто вызвать функцию, либо написать несколько классов, которые принимают ваш объект в качестве параметра конструктора, каждый с другим оператором перегрузки.
std :: cout << std :: cout
, который печатает это шестнадцатеричное значение.
Поскольку желаемый результат:
Value: 12
"правильный" действительно нужно переопределить оператор <<. Это часто означает, что вам нужно либо сделать его другом, либо сделать следующее:
class WhateverItIsYouReallyWantToPrint {
public:
void print(ostream &out) const {
// do whatever
}
};
ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
obj.print(out);
}
Если переопределение operator <<
для вашего класса не подходит, например, потому что существует несколько форматов, которые вы можете захотеть print, и вы хотите написать отдельную функцию для каждой из них, тогда вам следует либо отказаться от идеи объединения операторов и просто вызвать функцию, либо написать несколько классов, которые принимают ваш объект в качестве параметра конструктора, каждый с другим оператором перегрузки.
std :: cout << std :: cout
, который печатает это шестнадцатеричное значение.
Поскольку желаемый результат:
Value: 12
"правильный" действительно нужно переопределить оператор <<. Это часто означает, что вам нужно либо сделать его другом, либо сделать следующее:
class WhateverItIsYouReallyWantToPrint {
public:
void print(ostream &out) const {
// do whatever
}
};
ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
obj.print(out);
}
Если переопределение operator <<
для вашего класса не подходит, например, потому что существует несколько форматов, которые вы можете захотеть print, и вы хотите написать отдельную функцию для каждой из них, тогда вам следует либо отказаться от идеи объединения операторов и просто вызвать функцию, либо написать несколько классов, которые принимают ваш объект в качестве параметра конструктора, каждый с другим оператором перегрузки.
Поскольку желаемый результат:
Value: 12
«правильным» является переопределение оператора <<. Это часто означает, что вам нужно либо сделать его другом, либо сделать следующее:
class WhateverItIsYouReallyWantToPrint {
public:
void print(ostream &out) const {
// do whatever
}
};
ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
obj.print(out);
}
Если переопределение operator <<
для вашего класса не подходит, например, потому что существует несколько форматов, которые вы можете захотеть print, и вы хотите написать отдельную функцию для каждой из них, тогда вам следует либо отказаться от идеи объединения операторов и просто вызвать функцию, либо написать несколько классов, которые принимают ваш объект в качестве параметра конструктора, каждый с другим оператором перегрузки.
Поскольку желаемый результат:
Value: 12
«правильным» является переопределение оператора <<. Это часто означает, что вам нужно либо сделать его другом, либо сделать следующее:
class WhateverItIsYouReallyWantToPrint {
public:
void print(ostream &out) const {
// do whatever
}
};
ostream &operator<<(ostream &out, const WhateverItIsYouReallyWantToPrint &obj) {
obj.print(out);
}
Если переопределение operator <<
для вашего класса не подходит, например, потому что существует несколько форматов, которые вы можете захотеть print, и вы хотите написать отдельную функцию для каждой из них, тогда вам следует либо отказаться от идеи объединения операторов и просто вызвать функцию, либо написать несколько классов, которые принимают ваш объект в качестве параметра конструктора, каждый с другим оператором перегрузки.
There's no way to do what you're expecting there because of the order the functions are evaluated in.
Is there any particular reason you need to write directly to the ostream like that? If not, just have MyPrint return a string. If you want to use a stream inside MyPrint to generate the output, just use a strstream and return the result.
У вас есть два варианта. Первый, используя то, что у вас уже есть:
std::cout << "Value: ";
MyPrint(12, &std::cout);
std::cout << std::endl;
Другой, который больше похож на C ++, заключается в замене MyPrint ()
соответствующим std :: ostream & operator <<
. Уже есть один для int
, поэтому я сделаю его чуть более сложным:
#include <iostream>
struct X {
int y;
};
// I'm not bothering passing X as a reference, because it's a
// small object
std::ostream& operator<<(std::ostream& os, const X x)
{
return os << x.y;
}
int main()
{
X x;
x.y = 5;
std::cout << x << std::endl;
}
Вы хотите сделать MyPrint классом с оператором друга <<:
class MyPrint
{
public:
MyPrint(int val) : val_(val) {}
friend std::ostream& operator<<(std::ostream& os, const MyPrint& mp)
{
os << mp.val_;
return os;
}
private:
int val_;
};
int main(int argc, char** argv)
{
std::cout << "Value: " << MyPrint(12) << std::endl;
return 0;
}
Этот метод требует, чтобы вы вставили объект MyPrint в поток по вашему выбору. Если вам ДЕЙСТВИТЕЛЬНО нужна возможность изменить активный поток, вы можете сделать это:
class MyPrint
{
public:
MyPrint(int val, std::ostream& os) : val_(val), os_(os) {}
friend std::ostream& operator<<(std::ostream& dummy, const MyPrint& mp)
{
mp.os_ << mp.val_;
return os_;
}
private:
int val_;
std::ostream& os_
};
int main(int argc, char** argv)
{
std::cout << "Value: " << MyPrint(12, std::cout) << std::endl;
return 0;
}
Во-первых, нет причин не передавать ostream
по ссылке, а не по указателю:
std::ostream& MyPrint(int val, std::ostream& out) {
out << val;
return out;
}
Если вы действительно не хотите использовать ] std :: ostream & operator << (std :: ostream & os, TYPE)
, вы можете сделать это:
int main(int argc, char** argv){
std::cout << "Value: ";
MyPrint(12, std::cout) << std::endl;
return 0;
}
После изменения указателя на ссылку вы можете сделать следующее:
#include <iostream>
std::ostream& MyPrint(int val, std::ostream& out) {
out << val;
return out;
}
int main(int, char**) {
MyPrint(11, std::cout << "Value: ") << std::endl;
return 0;
}
Синтаксис для MyPrint
по существу аналогичен синтаксису развернутого оператора <<
, но с дополнительным аргументом.
В вашем случае ответ очевиден:
std::cout << "Value: " << 12 << std::endl;
Если этого недостаточно, объясните, какой результат вы хотите увидеть.