If I try to compile the following code I get the following compiler error (see code.) It compiles without error if std::endl is removed.
#include <iostream>
#include <sstream>
#include <utility>
namespace detail
{
template <class T>
void print(std::ostream& stream, const T& item)
{
stream << item;
}
template <class Head, class... Tail>
void print(std::ostream& stream, const Head& head, Tail&&... tail)
{
detail::print(stream, head);
detail::print(stream, std::forward<Tail>(tail)...);
}
}
template <class... Args>
void print(std::ostream& stream, Args&&... args)
//note: candidate function not viable: requires 3 arguments, but 4 were provided
{
std::stringstream ss;
detail::print(ss, std::forward<Args>(args)...);
stream << ss.rdbuf();
}
int main()
{
print(std::cout, "The answer is ", 42, std::endl);
//error: no matching function for call to 'print'
}
std::endl is a function template. When it is used, its template parameters have to be explicitly specified or deduced by the compiler.
std::ostream has an overload:
basic_ostream<charT,traits>& operator<<(
basic_ostream<charT,traits>& (*pf) (basic_ostream<charT,traits>&) );
When we use
std::cout << std::endl;
the compiler deduces the types to be used for std::endl. Since you don't have the ability to fall back on automatic type deduction when calling print, you have to be explicit about which version of std::endl you want to use.
The following should work:
print(std::cout, "The answer is ", 42, std::endl<char, std::char_traits<char>>);
Update
I used the following stripped down code to track the issue:
#include <iostream>
namespace detail
{
template <class T>
void print(std::ostream& stream, const T& item)
{
stream << item;
}
}
int main()
{
// detail::print(std::cout, std::endl);
detail::print(std::cout, std::endl<char, std::char_traits<char>>);
}
I think this is because template type deduction fails if you are passing a function template. It can't deduce the parameters to instantiate endl with.
Note that the definition of endl is:
template <class charT, class traits>
basic_ostream<charT,traits>& endl (basic_ostream<charT,traits>& os);
Simpler example:
template<class U> void func(U &u) { }
template<class T>
void print(const T &item) { }
int main()
{
print(func); // error: matching function for call to 'print(<unresolved overloaded function type>)'
}
Your error messages come about because it tries various ways to match your function call to the parameter pack but none of them worked.
You could avoid the problem by defining a simple endl yourself (Live Demo):
constexpr struct endl_ {
friend std::ostream& operator << (std::ostream& os, const endl_&) {
os << '\n'; // << std::flush;
return os;
}
} endl;
template <class... Args>
void print(std::ostream& stream, Args&&... args)
{
std::stringstream ss;
std::initializer_list<int>{0, (void(ss << std::forward<Args>(args)), 0)...};
stream << ss.rdbuf();
}
int main()
{
print(std::cout, "The answer is ", 42, endl);
//error: no matching function for call to 'print'
print(std::cout, "The answer is NOT ", 13, endl);
}
Related
Let's suppose I have the following class in an header file header.h:
#pargma once
#include <type_traits>
#include <iostream>
#include <sstream>
struct foo
{
// Utils struct
template <class T, class... Ts>
struct is_any: std::disjunction <std::is_same <T, Ts>... >{};
// Standard case
template <class T_os, class T, class... Args, typename = std::enable_if_t<is_any
<T_os, std::ostream, std::ostringstream>::value>>
const foo& operator () ( T_os& os, const T& first, const Args&... args ) const { os << "hello"; return *this; }
// Default std::ostream = std::cout case
template <class T, class... Args>
const foo& operator () ( const T& first, const Args&... args ) const { std::cout << "hello"; return *this; }
};
I defined a struct in which I overloaded the () operator two times: in the "standard case" the template is enabled if the T_os type is one of this list (std::ostream, std::ostringstream) and a message is sent to output using the T_os os object. In the "Default std::ostream = std::cout case" the template is called if T_os is not explicitly present and a message is sent to output using the std::ostream std::cout object.
A simple usage in main is:
#include "header.h"
int main()
{
foo foo_obj;
// Standard case
foo_obj ( std::cout, "first", "second" );
// Default std::ostream = std::cout case
foo_obj ( "first", "second" );
}
I want to know if it would be possible to merge the "standard case" operator () overload within the "Default std::ostream = std::cout case" operator () overload, in order to be able to perform the two operations shown in main using only an operator () overload instead of two. Thanks.
You could make operator() a front-end for the real implementation. You can then make it forward the arguments to the real implementation and add std::cout if needed.
Example:
struct foo {
template <class T, class... Args>
const foo& operator()(T&& first, Args&&... args) const {
if constexpr (std::is_base_of_v<std::ostream, std::remove_reference_t<T>>) {
// or std::is_convertible_v<std::remove_reference_t<T>*, std::ostream*>
// first argument is an `ostream`, just forward everything as-is:
op_impl(std::forward<T>(first), std::forward<Args>(args)...);
} else {
// add `std::cout` first here:
op_impl(std::cout, std::forward<T>(first), std::forward<Args>(args)...);
}
return *this;
}
private:
// implement the full operator function here. `os` is an `ostream` of some sort:
template <class S, class... Args>
void op_impl(S&& os, Args&&... args) const {
(..., (os << args << ' '));
os << '\n';
}
};
Demo
I used is_base_of_v<std::ostream, ...> instead of is_same to make it use any ostream (like an ostringstream or ofstream) if supplied as the first argument.
Maybe a solution with constexpr if (see here) and fold expressions will help.
Something like for example the below.
#include <type_traits>
#include <iostream>
#include <sstream>
template <class TFirst, class... TsRest>
void print(TFirst&& first, TsRest&& ... rest) {
if constexpr (std::is_same_v <std::remove_cvref_t<TFirst>, std::ostringstream> or
std::is_same_v <std::remove_cvref_t<TFirst>, std::ostream>) {
((first << rest << ' '), ...);
}
else {
std::cout << first << ' ';
((std::cout << rest << ' '), ...);
}
}
int main() {
print(1, 2);
std::ostringstream oss{};
print(oss, 3, 4);
std::cout << "\n\n" << oss.str() << "\n\n";
}
Maybe, this could give you an idea . . .
I have written myself the following function:
template <class Stream>
inline Stream& Print(Stream& in) { return in;}
template <class Stream, class Arg1, class... Args>
inline Stream& Print(Stream& sout, Arg1&& arg1, Args&&... args)
{
sout << arg1;
return Print(sout, args...);
}
It should make it useful to replace code like:
cout << "This took " << ns << " seconds with " << np << " packets.\n";
with
Print(cout, "This took ", ns, " seconds with ", np, " packets.\n");
And everything works fine, except that this function doesn't "tolerate" some manipulators. What is funny, only some of them. If you replace, for example, " packets.\n" with " packets.", endl, it will no longer compile. Although hex or setw(20) is fine. Where is the problem?
std::endl is a function template.
So it cannot be deduced as for overloaded functions.
static_cast<std::ostream& (*)(std::ostream&)>(&std::endl)
would select correct overload.
using Manipulator = std::ostream& (*)(std::ostream&);
Print(std::cout, "This took ", ns, " seconds with ", np, " packets.", Manipulator(std::endl));
Demo
Since C++14, you might even not hard code type of stream with an helper:
template <typename T>
struct ManipulatorImpl
{
ManipulatorImpl(T t) : t(t) {}
T t;
};
template <typename T>
std::ostream& operator << (std::ostream& os, ManipulatorImpl<T> m)
{
return m.t(os);
}
template <typename T>
ManipulatorImpl<T> make_ManipulatorImpl(T t) { return {t}; }
#define Manipulator(name) make_ManipulatorImpl([](auto& os) -> decltype((name)(os)) { return (name)(os); })
Demo
I can't explain the exact reason, but if I do something like this it doesn't throw an error:
endl<char, char_traits<char>>
My guess is that it doesn't seem to be able to do template type parameter inference.
The ostream is:
using ostream = basic_ostream<char, char_traits<char>>;
I'm trying to make a print function in C++ that takes in variable numbers of arguments and prints them each on their own line, like:
template<typename Ty, typename... Types>
void println(Ty cur_line, Types... other_lines)
{
std::cout << cur_line << '\n';
println(other_lines);
}
void println() { std::cout << std::flush; }
However, if Ty happens to be a std::vector<std::string>, I want to treat it differently (because I want to print every element of the vector on its own line). I looked into partial specialization, but there doesn't seem to be much that I could find on doing so with parameter packs. Here's what I tried:
template<typename Ty, typename... Types>
void println(Ty cur_line, Types... other_lines)
{
std::cout << cur_line << '\n';
println(other_lines);
}
template<typename... Types>
void println<std::vector<std::string>, Types...>
(std::vector<std::string> cur_line, Types... other_lines)
{
for (const auto& line : cur_line)
{
std::cout << line << '\n';
}
println(other_lines);
}
void println() { std::cout << std::flush; }
However, I'm getting an MSVC error C2768: "'println': illegal use of explicit template arguments".
Any suggestions or solutions would be warmly welcomed! For reference, I'm using Visual Studio 2019 Preview and its corresponding compiler version.
A simpler way would be to have a print function and overload that:
template < typename T >
void print(const T& line)
{
std::cout << line << '\n';
}
template < typename T >
void print(const std::vector<T>& line)
{
for (const auto& element : line)
{
print(element);
}
}
template<typename Ty, typename... Types>
void println(Ty cur_line, Types... other_lines)
{
print(cur_line);
println(other_lines);
}
void println() { std::cout << std::flush; }
You can do it like this:
/* main.cpp */
#include <iostream>
#include <vector>
#include <string>
using namespace std;
template <class T>
void PrintLine(const T &t)
{
cout << t << endl ;
}
template <class T>
void PrintLine(const vector<T> &t)
{
for(auto &obj : t ) PrintLine(obj);
}
template <class ... TT>
void PrintLines(const TT & ... tt)
{
( PrintLine(tt) , ... );
}
/* main() */
int main()
{
vector<string> list{"a","b","c"};
PrintLines(1,2,3,list);
return 0;
}
You can't partially specialize a function template, but you can overload it. Create a new overload of println that takes a std::vector<std::string> as the first argument and a general pack as the rest. Then do the special handling for the vector arg and forward the rest as before. Now your vectors will always be caught by the overload.
I write a variadic template to print all the arguments with recursion:
#include <iostream>
using std::ostream; using std::istream;
using std::cin; using std::cout; using std::endl;
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
if (sizeof...(rest)) {
os << t << ", ";
return myprint(os, rest...);
}
else
return os << t;
}
int main(int argc, char *argv[]) {
myprint(cout, "hello");
return 0;
}
But when I compiles it with g++ -std=c++1y, it complains:
error: no matching function for call to ‘myprint(std::ostream&)’
return myprint(os, rest...);
In the function myprint, I have checked the value of sizeof...(rest). And when it is 0, it will not call myprint(os, rest...). So I don't know why it will call myprint(std::ostream&).
And I have also searched for the related question, I have found that it needs a base case. But why do I need a base case, and can't sizeof... work in a variadic template?
And for the simple indefinite recursive case:
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", "; // print the first argument
return print(os, rest...); // recursive call; print the other arguments
}
The code above can't be compiled at all for the same error.
For the if statement you used, both the statement-true and statement-false must be valid, whether the condition yields to the result of true or false.
You can use constexpr if since C++17; when the value of condition is false, the statement-true will be discarded. e.g.
if constexpr (sizeof...(rest)) {
os << t << ", ";
return myprint(os, rest...);
}
else
return os << t;
If you can't use C++17, you can add another template overload for the case that the number of arguments is only one, to stop the recursion, e.g.
template <typename T>
ostream &myprint(ostream &os, const T &t) {
return os << t;
}
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", ";
return myprint(os, rest...);
}
LIVE
songyuanyao's answer explains why it's invalid and provides a solution for C++17. Alternatively, you could have a base case to myprint prior to that.
template <typename T>
ostream &myprint(ostream &os, const T &t) {
return os << t;
}
template <typename T, typename... Args>
ostream &myprint(ostream &os, const T &t, const Args&... rest) {
os << t << ", ";
return myprint(os, rest...);
}
Can you help me with the following problem ?
I am trying to use the variadic templates and pack expansion to write a logger. The problem is I know that operator<< must accept only two arguments - the second argument then becomes a whole pack, and I do not know how to expand 'const Args& ...rest' to 'const T& v, const Args& ...rest'
Can any guru explain how to re-write the variadic expression to achieve this goal ? The end game is to have code like:
log << "string" << 1 << 1.2;
being printed together at once.
(Please excuse the cout, it is just for example purposes. Idea is to collect all the arguments in oss_ and then print them once.).
The compiler current complains, which I understand is the issue with operator<< accepting only two arguments.
‘LogHandle& operator<<(LogHandle&, const T&, const Args& ...)’ must take exactly two argument
Here is the code:
#include <iostream>
#include <string>
#include <sstream>
class LogHandle {
public:
template<typename T>
friend LogHandle& operator<<(LogHandle& l, const T& v)
{
l.oss_ << v;
std::cout << "Value is: " << l.oss_.str().c_str();
l.oss_.str("");
l.oss_.clear();
return l;
}
template<typename T, typename... Args>
friend LogHandle& operator<<(LogHandle& l, const T& v, const Args&... rest)
{
l.oss_ << v << " ";
return l << (rest...);
}
std::ostringstream oss_;
};
int main(int, char**)
{
LogHandle log;
log << "String" << 1;
}
What you want to do is not possible exactly the way you want it, because the arity of operators is fixed—you cannot make them variadic.
However, you can instead use a proxy returned from your operator << to "collect" all the arguments in one place. Something like this:
class LogHandle
{
template<typename T>
friend LogProxy operator<<(LogHandle& l, const T& v)
{
LogProxy p(*this);
p << v;
return p;
}
void print(const std::ostringstream &oss)
{
std::cout << "Value is: " << oss.str();
}
};
struct LogProxy
{
LogHandle *handle;
std::ostringstream oss_;
LogProxy(LogHandle &l) : handle(&l) {}
LogProxy(LogProxy &&rhs) : handle(rhs.handle) { rhs.handle = nullptr; }
template <class T>
friend LogProxy& operator<< (LogProxy &p, const T &v)
{
p.oss_ << v;
return p;
}
~LogProxy()
{
if (handle) handle->print(oss_);
}
};