All,
I ran into a C++20 Visual Studio error C2593 ("Operator << is ambiguous") when compiling this simple program patterned from section 4.2 of the Vandevoorde, Josuttis and Gregor book "C++ Templates - The Complete Guide":
#include <iostream>
std::ostream& operator << (std::ostream& str, int s)
{
return str << s << ' ';
}
template <typename T>
void print(Args... args)
{
(std::cout << ... << args) << std::endl;
}
int main
{
print(1,2,3,4)
return 0;
}
I want the output to be "1 2 3 4", hence the operator redefinition to add a space after each displayed value. The C2593 error happens at this line,
return str << s << ' ';
but if I comment out that line, I get the same error at the fold expression line
(std::cout << ... << args) << std::endl;
I'm just learning C++ templates, so, can anyone spot what I'm doing wrong ? Thanks!
All,
I ran into a C++20 Visual Studio error C2593 ("Operator << is ambiguous") when compiling this simple program patterned from section 4.2 of the Vandevoorde, Josuttis and Gregor book "C++ Templates - The Complete Guide":
#include <iostream>
std::ostream& operator << (std::ostream& str, int s)
{
return str << s << ' ';
}
template <typename T>
void print(Args... args)
{
(std::cout << ... << args) << std::endl;
}
int main
{
print(1,2,3,4)
return 0;
}
I want the output to be "1 2 3 4", hence the operator redefinition to add a space after each displayed value. The C2593 error happens at this line,
return str << s << ' ';
but if I comment out that line, I get the same error at the fold expression line
(std::cout << ... << args) << std::endl;
I'm just learning C++ templates, so, can anyone spot what I'm doing wrong ? Thanks!
Share asked Mar 8 at 22:44 AlbertusAlbertus 666 bronze badges2 Answers
Reset to default 2Your code has a few problems. Each is pretty minor individually, but they're still enough to keep it from working.
First of all, there's an existing overload of operator<<
to insert an int
into an ostream
, so you don't need to write that yourself (and attempting to do so as you've done creates an ambiguous overload, so the code won't compile). One way to write out the space after each item is to convert each to a string, and add the space to the end of the string.
Second, you haven't defined print
as a variadic template, even though you've tried to use it as one.
Third, you need an empty pair of parens after main
to get a function definition.
Fixing those gives us something like this:
#include <iostream>
#include <string>
template <typename ...Args>
void print(Args... args)
{
(std::cout << ... << (std::to_string(args) + ' ')) << std::endl;
}
int main()
{
print(1,2,3,4);
}
And this works.
live on Godbolt
As a rather minor aside, I'd personally write a new-line ('\n'
) to the stream rather than using std::endl
. In this case it's not a big deal, but std::endl
flushes the output stream, which is rarely desired, but can cause a pretty serious slow-down if done frequently.
Thanks, all, @TedLyngmo told me what I did wrong. I cannot overload operator << for standard types, so, I needed to create a class and use it instead to unpack my template parameters. Here's a sample code that works, again, patterned from that Vandervoode, Josuttis and Gregor book:
#include <iostream>
#include <string>
template<typename T>
class AddSpace
{
private:
T const& ref;
public:
AddSpace(T const& r) : ref(r) {}
friend std::ostream& operator << (std::ostream& str, AddSpace<T> s)
{
return str << s.ref << ' ';
}
};
template <typename... Args>
void print(Args... args)
{
// Fold expression unpacks args, creates one AddSpace object per arg, and outputs each AddSpace::ref to std::cout.
(std::cout << ... << AddSpace(args)) << std::endl;
}
int main()
{
print(1, 2, 3, 4);
return 0;
}
Creating a user class, overloading operator << to take values from that class, and using it to unpack the template parameters, apparently does the job. It's a bit complicated but it works. So, again, thanks to you all!