stuck --- Creating an Operator Template in C++ - c++

I am creating a class SpyOutput that mimics cout, and I am trying to use a template so I don't have to overload the << operator 4 times (one for each data type):
#include <iostream>
#include <sstream>
using namespace std;
class SpyOutput
{
ostream *os;
stringstream ss;
int sum, temp;
public:
SpyOutput(ostream *s):os(s), sum(0){}
template <class T>
SpyOutput& operator<<(T x)
{
ss << x;
*os << x;
return *this;
}
};
int main(void)
{
SpyOutput spy(&cout);
spy << "Hello" << endl;
spy << "1235" << endl;
spy << 'z' << endl;
spy << 4.56 << endl;
return 0;
}
I can't get it to compile, it doesn't seem to recognize my template. Any ideas? The G++ error message is
main.cpp: In function 'int main()':
main.cpp:24:20: error: no match for 'operator<<' (operand types are 'SpyOutput' and '<unresolved overloaded function type>')
spy << "Hello" << endl;
^
main.cpp:24:20: note: candidates are:
main.cpp:13:16: note: template<class T> SpyOutput& SpyOutput::operator<<(T)
SpyOutput& operator<<(T x)
^
main.cpp:13:16: note: template argument deduction/substitution failed:
main.cpp:24:23: note: couldn't deduce template parameter 'T'
spy << "Hello" << endl;
^

The key part of the error message is "template argument deduction/substitution failed". endl is not an object, it's not even a function. It is a function template, which is a "cookie cutter" used to generate an infinite number of cookie-functions. When << to a ostream, the the compiler sees if any of the potential << functions can clarify what the template arguments should be. And there exists this overload:
ostream& operator<< (ostream& (*pf)(ostream&));
When the compiler checks this overload, it realizes that it can unambiguously specialize endl as a ostream& (*)(ostream&), and so selects this overload and does the implicit specialization matching the stream's type. Luckily, all you have to do is also provide the above function overload, and hopefully this magic will work for you as well.
As a note, ostreams have two other important overloads as members you'll have to add as well:
ostream& operator<< (ios& (*pf)(ios&));
ostream& operator<< (ios_base& (*pf)(ios_base&));
It's also worth mentioning that your function is attempting to make copies of all objects you stream, which can cause it to fail or act wierd. A more sane idea is to use a universal reference. Or at least capture by const reference.
//if T is a template, then T&& is a universal reference. A perfect match for everything
//if T were not a template, it would be an rvalue reference. Totally unrelated.
template <class T> SpyOutput& operator<<(T&& x) {
ss << x;
*os << x;
return *this;
}

Your code fails simply because std::endl is a function template, and therefore the compiler needs to know which instantiation of the template you want to use. The standard IOStream classes have separate overloads for manipulators, and they explicitly specify the template instantiation. You can do that as well:
SpyOutput& operator<<(std::ostream& (*manip)(std::ostream&))
{
if (os) manip(*os);
return *this;
}
Now when you do spy << std::endl this will instantiate std::endl<char, std::char_traits<char>> which is valid, and the code will work. Though in general I wouldn't recreate an entire stream class but rather use the std::streambuf interface.

Related

<< operator overloading and template specialization

As part of study purpose, I was just playing with template specialization together with operator overloading
#include <iostream>
template<class T>
void operator<<(std::ostream& COUT,T val)
{
std::operator<<(COUT,val); //works for basic data types
}
//specializing for const char*
template<>
void operator<<(std::ostream& COUT,const char* val)
{
std::operator<<(COUT,val);
}
int main()
{
std::cout<<"samplestring"; //getting error here
return 0;
}
I am getting following error which I cannot figure out.
<source>:17:14: error: ambiguous overload for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'const char [13]')
17 | std::cout<<"samplestring";
| ~~~~~~~~~^~~~~~~~~~~~~~~~
| | |
| | const char [13]
| std::ostream {aka std::basic_ostream<char>}
what is the problem here
Thank you..!
The problem is there is already operator<<(std::ostream& COUT,const char* val) defined by the standard library.
So now there are two symbols
std::operator<<(std::ostream& ostream,const char* val);
operator<<(std::ostream& COUT,const char* val); // YOURS
Because the symbols are different, there are no multiple-definition errors.
For a call std::cout << "Hello", the compiler searches for all operator<< functions currently defined at the call site. That looks like it is just your function, but the compiler also looks into all namespaces in which the passed arguments are defined. In this case it is std:: namespace and there the compiler finds the STL version. That is called argument dependent lookup(ADL).
Since both functions are templates and neither is more specialized than the other, the call is ambiguous.
Please do not use all capital letters as variable COUT, that is usually reserved for macros, with one-letter template parameters being exception T.
//works for basic data types
That is also not true, std::cout<<5; will NOT call your definition with T. Because there exists std::ostream::operator<<(int v) method. Same lookup happens but since this method is not a template, it is a better candidate and thus chosen. Your template function is never called.

Compilation failure when inner class uses outer class template parameter but only when using `ostream`

I run into a compiler error when an inner class uses the template parameter of the outer class, and I instantiate an output stream operator on the outer class on the member of the inner type.
I have spent a good bit of time trying to resolve this problem. I believe the following sources come close but I still do not understand why I am getting a compilation failure.
https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types
https://msdn.microsoft.com/en-us/library/71dw8xzh.aspx
Here is the code:
#include <iostream>
#include <vector>
template <typename T>
struct Outer
{
struct Inner
{
Inner(const T& val = T());
T data_;
}; // end class Inner
Outer();
void AddInnerChildToOuter(const T& data);
std::vector<typename Outer<T>::Inner> innerChildren_;
}; // end class Outer
// Inner constructor
template <typename T>
Outer<T>::Inner::Inner(const T& val) : data_(val)
{
}
template <typename T>
std::ostream& operator<<(std::ostream& strm, // Line 27
const typename Outer<T>::Inner& gn)
{
strm << gn.data_ << std::endl;
return strm;
}
// Outer constructor
template <typename T>
Outer<T>::Outer()
{
}
template <typename T>
void Outer<T>::AddInnerChildToOuter(const T& data)
{
typename Outer<T>::Inner node(data);
innerChildren_.push_back(node);
}
template <typename T>
std::ostream& operator<<(std::ostream& strm, const Outer<T>& g)
{
for (size_t i = 0; i < g.innerChildren_.size(); ++i)
std::cout << g.innerChildren_[i] << std::endl; // Line 51
return strm;
}
int main()
{
Outer<int> g;
g.AddInnerChildToOuter(3);
g.AddInnerChildToOuter(5);
std::cout << g << std::endl; // Line 60
return 0;
}
I get a compiler error for the ostream operator << on the outer that calls the corresponding output stream operator for the inner. I am not posting the entire litany of the compiler's error messages; just what I consider to be relevant.
$ g++ -Wall -W -Wextra -pedantic -ansi OuterInnerArgh.cpp
OuterInnerArgh.cpp: In instantiation of ‘std::ostream& operator<<(std::ostream&, const Outer<T>&) [with T = int; std::ostream = std::basic_ostream<char>]’:
OuterInnerArgh.cpp:60:18: required from here
OuterInnerArgh.cpp:51:19: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘const Outer<int>::Inner’)
std::cout << g.innerChildren_[i] << std::endl;
~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
(snipped compiler's attempts at various ostream overloads; more compiler error messages below)
OuterInnerArgh.cpp:27:15: note: candidate: template<class T> std::ostream& operator<<(std::ostream&, const typename Outer<T>::Inner&)
std::ostream& operator<<(std::ostream& strm,
^~~~~~~~
OuterInnerArgh.cpp:27:15: note: template argument deduction/substitution failed:
OuterInnerArgh.cpp:51:19: note: couldn't deduce template parameter ‘T’
std::cout << g.innerChildren_[i] << std::endl;
~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
OuterInnerArgh.cpp:48:15: note: candidate: template<class T> std::ostream& operator<<(std::ostream&, const Outer<T>&)
std::ostream& operator<<(std::ostream& strm, const Outer<T>& g)
^~~~~~~~
OuterInnerArgh.cpp:48:15: note: template argument deduction/substitution failed:
OuterInnerArgh.cpp:51:19: note: ‘const Outer<int>::Inner’ is not derived from ‘const Outer<T>’
std::cout << g.innerChildren_[i] << std::endl;
~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
(snipped rest of compiler errors)
Please let me know why I encounter a compiler error -
Even though I have an ostream operator << for typename Outer<T>::Inner&
Even when I have "sprinkled" the typename "magic-dust" wherever relevant
Only for the outer ostream operator, not for the constructors or the inner ostream operator (the latter probably not instantiated at all?)
Why does the compiler say ‘const Outer<int>::Inner’ is not derived from ‘const Outer<T>’? (Yes, there is no inheritance, but the inner type definition is nested within the outer)
You got compile error because non-deduced context causes template argument deduction failing.
In the following cases, the types, templates, and non-type values that are used to compose P do not participate in template argument deduction, but instead use the template arguments that were either deduced elsewhere or explicitly specified. If a template parameter is used only in non-deduced contexts and is not explicitly specified, template argument deduction fails.
The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
For example, if you specify the template argument explicitly (in ugly style) it would compile. In the operator<< for Outer:
operator<< <T> (strm, g.innerChildren_[i]);
// ^^^
You can make the operator<< non-template (to bypass the type deduction trouble), then you have to define it inside the class definition as friend. e.g.
struct Inner
{
Inner(const T& val = T());
T data_;
friend std::ostream& operator<<(std::ostream& strm,
const Inner& gn)
{
strm << gn.data_ << std::endl;
return strm;
}
};
LIVE
Fix this
std::cout << g.innerChildren_[i] << std::endl; // Line 51
to be
std::cout << g.innerChildren_[i].data_ << std::endl; // Line 51
Because you are trying to use the operator << where it is not defined
If you depend on the defined operator in line (27), modify line (50) to call it properly, as follows
for (size_t i = 0; i < g.innerChildren_.size(); ++i)
{
operator<< <T>(strm, g.innerChildren_[i]);
strm << std::endl;
}

C++ function header matching: how does matching work when const and templates are both involved?

I had a templated function that I wished to call. This is (a trimmed-down version of) the header:
template <typename Item>
void print (shared_ptr<const MyContainer<Item>> stuff, ostream& out)
which I tried to call with a line like this:
print (make_shared<MyContainer<int>>(42), cerr);
But the compiler complained that there was no match. What confuses me is that the const mismatch is not a problem, because if I redeclare my function to omit the template it works:
void print (shared_ptr<const MyContainer<int>> stuff, ostream& out) //matches!
On the other hand, if I omit constness, the templated version does work:
template <typename Item>
void print (shared_ptr<MyContainer<Item>> stuff, ostream& out) //also matches!
But I should be able to write a function over const things and pass it a non-const value (which the function will then just not modify), right? Indeed, if I go back to non-managed pointers, the corresponding old way to write the header would have been
template <typename Item>
void print (const MyContainer<Item>* stuff, ostream& out)
and indeed then a call to
print (new MyContainer<int>(42), cerr); //yet another match!
once again just fine.
So, what is it about this particular cocktail of shared_ptr, templates, and const that causes the compiler to be unable to find the matching function? (Running g++ 8.2.1, and clang++ 7.0.1 seems to produce the same result.)
Concerning const-ness of pointee, std::shared_ptr behaves a bit different than raw-pointers.
A std::shared_ptr<T> is not the same as a std::shared_ptr<const T>. It's even not that compatible to allow an implicit conversion. (The error message in Daniels answer says this quite literally.)
It doesn't work for the same reason like in the following (counter) example:
template <typename T>
struct ContainerT {
T a;
ContainerT(T a): a(a) { }
ContainerT(const ContainerT&) = default;
ContainerT& operator=(const ContainerT&) = default;
};
int main()
{
ContainerT<int> a(42);
ContainerT<const int> b(a);
return 0;
}
Output:
g++ (GCC) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
main.cpp: In function 'int main()':
main.cpp:15:28: error: no matching function for call to 'ContainerT<const int>::ContainerT(ContainerT<int>&)'
ContainerT<const int> b(a);
^
main.cpp:8:3: note: candidate: 'constexpr ContainerT<T>::ContainerT(const ContainerT<T>&) [with T = const int]'
ContainerT(const ContainerT&) = default;
^~~~~~~~~~
main.cpp:8:3: note: no known conversion for argument 1 from 'ContainerT<int>' to 'const ContainerT<const int>&'
main.cpp:7:3: note: candidate: 'ContainerT<T>::ContainerT(T) [with T = const int]'
ContainerT(T a): a(a) { }
^~~~~~~~~~
main.cpp:7:3: note: no known conversion for argument 1 from 'ContainerT<int>' to 'int'
Live Demo on coliru
In the case of std::shared_ptr, there is a way to circumvent this issue
→ a std::const_pointer_cast can be used:
#include <iostream>
#include <memory>
template <typename T>
struct ContainerT {
T a;
ContainerT(T a): a(a) { }
};
template <typename T>
void print(std::shared_ptr<const ContainerT<T>> ref, std::ostream &out)
{
out << "print: '" << ref->a << "'\n";
}
int main()
{
print(std::make_shared<const ContainerT<int>>(42), std::cout);
print(std::const_pointer_cast<const ContainerT<int>>(std::make_shared<ContainerT<int>>(42)), std::cout);
return 0;
}
Output:
print: '42'
print: '42'
Live Demo on coliru
For convenience, the const-cast might be done in another function template:
#include <iostream>
#include <memory>
template <typename T>
struct ContainerT {
T a;
ContainerT(T a): a(a) { }
};
template <typename T>
void print(std::shared_ptr<const ContainerT<T>> ref, std::ostream &out)
{
out << "print const: '" << ref->a << "'\n";
}
template <typename T>
void print(std::shared_ptr<ContainerT<T>> ref, std::ostream &out)
{
out << "print non-const: ";
print(std::const_pointer_cast<const ContainerT<T>>(ref), out);
}
int main()
{
print(std::make_shared<const ContainerT<int>>(42), std::cout);
print(std::make_shared<ContainerT<int>>(42), std::cout);
return 0;
}
Output:
print const: '42'
print non-const: print const: '42'
Live Demo on coliru
Here is a simplified code:
template <typename T>
void f(std::shared_ptr<const std::vector<T>>) { }
void g(std::shared_ptr<const std::vector<int>>) { }
int main() {
f(std::make_shared<std::vector<int>>()); // ERROR
g(std::make_shared<std::vector<int>>()); // OK
}
To understand what happens, read the error message, e.g., the one printed by g++:
...
note: template argument deduction/substitution failed:
note: types 'const std::vector<T>' and 'std::vector<int>' have incompatible cv-qualifiers
It tells you that the problem is with template argument deduction/substitution. The C++ rules seemingly do not allow this type of deduction. (If I have some time, I will try to find a relevant part of the Standard).
However, you can skip the template argument deduction by providing an explicit template argument:
f<int>(std::make_shared<std::vector<int>>()); // OK

lambda converted to bool instead of deducing function-pointer-type

I wanted to implement a overload for operator<< that allowed me to call a given function and output the result.
I therefore wrote an overload, but the conversion to bool is selected and when writing a function myself, it would not compile.
EDIT: Know that I do not want to call the lambda,
but instead pass it to the function where it should be called with a default constructed parameter list.
I have appended my code:
#include <iostream>
template<typename T>
void test(T *) {
std::cout << "ptr" << std::endl;
}
template<typename T>
void test(bool) {
std::cout << "bool" << std::endl;
}
template<typename Ret, typename ...Args>
void test(Ret(*el)(Args...)) {
std::cout << "function ptr\n" << el(Args()...) << std::endl;
}
template<typename Char_T, typename Char_Traits, typename Ret, typename ...Args>
std::basic_ostream<Char_T, Char_Traits>& operator<<(
std::basic_ostream<Char_T, Char_Traits> &str, Ret(*el)(Args...)) {
return str << el(Args()...);
}
int main() {
std::boolalpha(std::cout);
std::cout << []{return 5;} << std::endl; // true is outputted
test([]{return 5;}); // will not compile
}
I use gcc 7.3.1 with the version flag -std=c++14.
EDIT: Error message:
main.cc: In function ‘int main()’:
main.cc:25:23: error: no matching function for call to ‘test(main()::<lambda()>)’
test([]{return 5;});
^
main.cc:5:6: note: candidate: template<class T> void test(T*)
void test(T *) {
^~~~
main.cc:5:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘T*’ and ‘main()::<lambda()>’
test([]{return 5;});
^
main.cc:9:6: note: candidate: template<class T> void test(bool)
void test(bool) {
^~~~
main.cc:9:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: couldn't deduce template parameter ‘T’
test([]{return 5;});
^
main.cc:13:6: note: candidate: template<class Ret, class ... Args> void test(Ret (*)(Args ...))
void test(Ret(*el)(Args...)) {
^~~~
main.cc:13:6: note: template argument deduction/substitution failed:
main.cc:25:23: note: mismatched types ‘Ret (*)(Args ...)’ and ‘main()::<lambda()>’
test([]{return 5;});
Your problem here is that Template Argument Deduction is only done on the actual argument passed to test. It's not done on all possible types that the argument could possibly converted to. That might be an infinite set, so that's clearly a no-go.
So, Template Argument Deduction is done on the actual lambda object, which has an unspeakable class type. So the deduction for test(T*) fails as the lambda object is not a pointer. T can't be deduced from test(bool), obviously. Finally, the deduction fails for test(Ret(*el)(Args...)) as the lambda object is not a pointer-to-function either.
There are a few options. You might not even need a template, you could accept a std::function<void(void)> and rely on the fact that it has a templated constructor. Or you could just take a test(T t) argument and call it as t(). T will now deduce to the actual lambda type. The most fancy solution is probably using std::invoke, and accepting a template vararg list.
Even though non-capturing lambdas have an implicit conversion to function pointers, function templates must match exactly for deduction to succeed, no conversions will be performed.
Therefore the easiest fix is to force the conversion with a +
int main() {
std::boolalpha(std::cout);
std::cout << []{return 5;} << std::endl; // true is outputted
test(+[]{return 5;});
// ^
}
template<typename T>
void test(bool) {
std::cout << "bool" << std::endl;
}
Template is not needed. In fact you overload functions, not templates. Replace it with
void test(bool) {
std::cout << "bool" << std::endl;
}
Now your sample will compile.

Priority and ambiguity of explicit conversion operator templates

I've been playing around with templated explicit conversion operators in my project, to implement explicit conversion from custom variant-like type. The minimal example reproducing my problem looks like the following (in C++14 mode):
#include <iostream>
#include <stdexcept>
#include <cmath>
using namespace std;
class A
{
public:
template<typename T> explicit operator T() const // 1
{
cout << "operator T" << endl;
return T();
}
template<typename T> explicit operator const T&() const // 2
{
cout << "operator const T&" << endl;
throw runtime_error("operator const T&");
}
template<typename T> explicit operator T&() // 3
{
cout << "operator T&" << endl;
throw runtime_error("operator T&");
}
};
int main(int, char**)
{
try
{
const A& a = A();
cout << abs(static_cast<double>(a) - 3.14) << endl;
}
catch (const runtime_error&)
{
}
return 0;
}
The problem I faced is the operator chosen for the static_cast conversion. With the GCC it's sort of expected (1) case. The output is:
operator T
3.14
But Clang refuses to compile this with the following output:
main.cpp:37:20: error: ambiguous conversion for static_cast from 'const A' to 'double'
cout << std::abs(static_cast<double>(a) - 3.14) << endl;
^~~~~~~~~~~~~~~~~~~~~~
main.cpp:10:32: note: candidate function [with T = double]
template<typename T> explicit operator T() const
^
main.cpp:16:32: note: candidate function [with T = double]
template<typename T> explicit operator const T&() const
^
1 error generated.
Why Clang considers conversion (2), when it apparently would require additional constructor call in the conversion sequence, while (1) wouldn't? And is it right (and GCC is then wrong) doing so?
static_cast performs either implicit conversion or direct initialisation. In your case, implicit conversion is not viable, but direct initialisation is because static_cast considers explicit constructors and conversion functions. So my guess is that clang (in my opinion correctly) identifies that there are two possible direct intialisations and complains accordingly. Not sure what is going on inside GCC, maybe it defaults to operator T() if it can find one, regardless of whether other ones exist.