The following prototype is intended to make synchronized print:
#include <iostream>
#include <string>
#include <sstream>
#include <mutex>
#include <Windows.h> // for OutputDebugString
std::mutex sync_mutex;
template<typename T>
void sync_print_impl(std::ostringstream& str, const T& t)
{
str << t << " ";
}
template<typename ... Args>
void sync_print_impl(std::ostringstream& str, Args ... args)
{
str; // prevents unused variable warning when sync_print is called without arguments
(..., sync_print_impl(str, args));
}
template <typename... Args>
void sync_print(Args... args)
{
std::ostringstream s;
sync_print_impl(s, args...);
{
std::lock_guard<std::mutex> lg(sync_mutex);
std::cout << s.str() << std::endl;
}
}
Simple test is OK:
void test1()
{
sync_print("abc", 1, 5.5); // prints abc 1 5.5
sync_print(); // prints empty string
}
The following test shows, that parameters are copied:
class test_class
{
public:
test_class(int n)
: data(n)
{
OutputDebugString(L"test_class\n");
}
test_class(const test_class& other)
{
data = other.data;
OutputDebugString(L"copy constructor\n");
}
test_class& operator=(const test_class& other)
{
data = other.data;
OutputDebugString(L"operator=\n");
return *this;
}
~test_class()
{
OutputDebugString(L"~test_class\n");
}
friend std::ostream& operator<<(std::ostream& os, const test_class& t);
private:
int data{};
};
std::ostream& operator<<(std::ostream& os, const test_class& t)
{
os << t.data;
return os;
}
void test2()
{
test_class t(5);
sync_print(t); // prints 5
}
OutputDebugString result is:
test_class
copy constructor
~test_class
~test_class
How to change sync_print to ensure that parameters are passed by reference?
You do not need extra template function sync_print_impl. Following should be enough, as you can make use of c++17 's fold expression.
In addition, use perfect forwarding to avoid coping the object.
template<typename... Args>
void sync_print_impl(std::ostringstream& str, Args&&... args)
// ^^^^^^^^^^^^^^^^
{
((str << std::forward<Args>(args) << " "), ...);
}
template <typename... Args>
void sync_print(Args&&... args)
// ^^^^^^^^^^^^^^^
{
std::ostringstream s;
sync_print_impl(s, std::forward<Args>(args)...);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ... code
}
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'm trying to construct the perfect forwarded (zero copied) construction using nested lambda captures.
I expect that there should be zero copy constructions, but something is broken.
I move from variadic arg. pack to tuple (moved ok) then I pass the tuple (moved ok) to the std::apply and in final nested lambda I assemble another tuple (expected to be moved ok but Wrapper CTOR is COPY not MOVE:
#include <iostream>
// tuple printer (ignore it)
template<typename Type, unsigned N, unsigned Last>
struct tuple_printer {
static void print(std::ostream& out, const Type& value) {
out << std::get<N>(value) << ", ";
tuple_printer<Type, N + 1, Last>::print(out, value);
}
};
template<typename Type, unsigned N>
struct tuple_printer<Type, N, N> {
static void print(std::ostream& out, const Type& value) {
out << std::get<N>(value);
}
};
template<typename... Types>
std::ostream& operator<<(std::ostream& out, const std::tuple<Types...>& value) {
out << "(";
tuple_printer<std::tuple<Types...>, 0, sizeof...(Types) - 1>::print(out, value);
out << ")";
return out;
}
// THE FUNCTION that returns lambda:
template <class ... Args>
auto f(Args && ... args)
{
// v--- args is a tuple<arg1, arg2, arg3 ...>
return [args_upper = std::make_tuple(std::forward<Args>(args)...)]()
{
// v-- lower "args" is a restored list of arguments - moved from the upper tuple "args"
return std::apply([](auto && ... args) {
// v--- here the Wrapper COPY-CTOR is called instead of moved from
return std::make_tuple(std::forward<decltype(args)>(args)...);
}, std::move(args_upper));
};
}
struct Wrapper {
Wrapper() {
std::cout << "CTOR ";
}
Wrapper(const Wrapper & r) {
std::cout << "COPY-CTOR ";
}
Wrapper(Wrapper&& r) {
std::cout << "MOVE-CTOR ";
}
int w = 42;
friend std::ostream& operator<<(std::ostream& out, const Wrapper& w);
};
std::ostream& operator<<(std::ostream& out, const Wrapper& w) {
out << w.w;
return out;
}
int main() {
auto l = f(1,2.f,"st", Wrapper{});
auto t = l(); // t is tuple
std::cout << t; // tuple printer
// std::cout << l();
}
Gives an output CTOR MOVE-CTOR COPY-CTOR (1, 2, st, 42)
return [args_upper = std::make_tuple(std::forward<Args>(args)...)]()
change this to
return [args_upper = std::make_tuple(std::forward<Args>(args)...)]() mutable
args_upper is implicitly const unless you make your lambda mutable. That'll block move semantics.
Here's a fun challenge.
I wanted to created some boilerplate that allows the clean handling of precondition failures using syntax similar to perl's x or die("reason") approach.
I came up with this deleter:
struct do_exit {
[[noreturn]]
void operator()(void*) const noexcept {
std::exit(code_);
}
int code_;
};
Which we can use to manage the "deletion" of a temporary std::unique_ptr which is maybe pointing at std::cerr:
struct exit_stream
{
exit_stream(int code, std::ostream& os)
: stream_(std::addressof(os), do_exit { code })
{}
std::ostream& as_stream() const { return *stream_; }
operator bool() const { return bool(*stream_); }
template<class T>
friend auto operator<<(const exit_stream& es, T const& t) -> exit_stream const&
{
es.as_stream() << t;
return es;
}
std::unique_ptr<std::ostream, do_exit> stream_;
};
Created with the following function:
exit_stream die(int code = 100)
{
return exit_stream(code, std::cerr);
}
Now we can write the following program:
int main(int argc, char* argv[]) {
// preconditions
argc >= 2 or die(4) << "usage: myprog <inputfile>\n";
auto input = std::ifstream(argv[1]);
input or die(100) << "failed to open " << argv[1] << "\n";
}
This works because when the exit_stream is returned as a temporary, it must be moved (unique_ptr deletes the copy operator). unique_ptr guarantees that the moved-from pointer will be null. It also guarantees that the deleter will only be called if the unique_ptr is not null. Therefore, exit will only be called after all streaming operations have been executed at the call site.
However, the obvious failing is that I can't write:
auto input = std::ifstream(argv[1]]) or die() << "failed to open " << argv[1] << "\n";
Because if I did, input would be a bool.
Here's my question. Can you think of a way to produce the required effect, or as close to it as possible?
I really want to avoid this, for reasons of efficiency in the passing case, and for clarity and elegance:
auto input = (std::ifstream(argv[1]]) or die() << "failed to open " << argv[1] << "\n").get();
Full code:
#include <fstream>
#include <iostream>
#include <cstdlib>
struct do_exit {
[[noreturn]]
void operator()(void*) const noexcept {
std::exit(code_);
}
int code_;
};
struct exit_stream
{
exit_stream(int code, std::ostream& os)
: stream_(std::addressof(os), do_exit { code })
{}
std::ostream& as_stream() const { return *stream_; }
operator bool() const { return bool(*stream_); }
template<class T>
friend auto operator<<(const exit_stream& es, T const& t) -> exit_stream const&
{
es.as_stream() << t;
return es;
}
std::unique_ptr<std::ostream, do_exit> stream_;
};
exit_stream die(int code = 100)
{
return exit_stream(code, std::cerr);
}
int main(int argc, char* argv[]) {
// preconditions
argc >= 2 or die(4) << "usage: myprog <inputfile>\n";
auto input = std::ifstream(argv[1]);
input or die(100) << "failed to open " << argv[1];
}
OK, here's my first attempt. I'm a little concerned about redundant construction because of the lack of short-circuiting, but the syntax is what I wanted.
Comments / improvements welcome!
#include <fstream>
#include <iostream>
#include <utility>
#include <iomanip>
namespace detail {
struct tuple_emitter {
tuple_emitter(std::ostream &os) : os(os) {}
template<class...Refs>
void operator()(std::tuple<Refs...> const &t) const {
emit_impl(t, std::make_index_sequence<sizeof...(Refs)>());
}
private:
template<class T>
void emit_impl(T const &t) const {
os << t;
}
// make sure we handle lazy manipulators
void emit_impl(std::ios_base (* f)(std::ios_base &)) const
{
f(os);
}
template<class Tie, std::size_t...Is>
void emit_impl(Tie const &refs, std::index_sequence<Is...>) const {
using expand = int[];
void(expand{0,
((emit_impl(std::get<Is>(refs))), 0)...});
os << std::endl;
};
std::ostream &os;
};
// a class that emits a number of references to std::cerr and then
// exits
template<class...Refs>
struct dier {
dier(int code, std::tuple<Refs...> t) : code(code), emitter(std::cout), refs_(t) {}
template<class...Others, class Ref>
dier(dier<Others...> const &original, Ref const &r)
: code(original.code), emitter(original.emitter), refs_(std::tuple_cat(original.refs_, std::tie(r))) {};
void operator()() const {
emitter(refs_);
std::exit(code);
}
int code;
tuple_emitter emitter;
std::tuple<Refs&...> refs_;
};
template<class...Refs, class Ref>
auto operator<<(dier<Refs...> original, Ref const &ref) {
return dier<Refs..., const Ref &>(original, ref);
};
template<class T, class...Refs>
T operator||(T &&t, dier<Refs...> death) {
if (!t) {
death();
}
return std::move(t);
};
template<class T, class...Refs>
T const &operator||(T &t, dier<Refs...> death) {
if (!t) {
death();
}
return t;
};
}
auto die(int code = 100) {
return detail::dier<>(code, std::make_tuple());
}
int main(int argc, char *argv[]) {
// preconditions
argc >= 2 or die(4) << "usage: myprog <inputfile>\n";
auto input = std::ifstream(argv[1]) or die(5) << "failed to open " << std::setfill('-') << std::setw(10) << argv[1] << " and here is a hex number " << std::hex << 40;
}
Expected outputs:
With no arguments:
usage: myprog <inputfile>
With one argument "foo.txt":
failed to open ---foo.txt and here is a hex number 28
Update after Yakk's suggestions
got it down to this - which is much cleaner:
#include <fstream>
#include <iostream>
#include <utility>
#include <iomanip>
namespace notstd {
namespace detail {
template<class F, class T, std::size_t...Is>
void apply_impl(F&& f, T&& t, std::index_sequence<Is...>)
{
using expand = int[];
void(expand{0,
((f(std::get<Is>(t))), 0)...});
};
}
template<class F, class...Ts>
void apply(F&& f, std::tuple<Ts...> const& t)
{
detail::apply_impl(std::forward<F>(f), t, std::make_index_sequence<sizeof...(Ts)>());
};
struct apply_to_stream
{
apply_to_stream(std::ostream& os)
: os(os)
{}
template<class T>
std::ostream& operator()(T&& t) const
{
return os << t;
};
std::ostream& operator()(std::ios_base& (*f)(std::ios_base&)) const
{
f(os);
return os;
};
std::ostream& os;
};
}
namespace detail {
template<class Tuple>
struct dier {
constexpr dier(int code, Tuple t) : code(code), refs_(std::move(t)) {}
void operator()() const {
notstd::apply(notstd::apply_to_stream(std::cout), refs_);
std::cout << '\n';
std::exit(code);
}
int code;
Tuple refs_;
};
template<class Tie>
constexpr auto make_dier(int code, Tie&& t) {
return detail::dier<Tie>(code, std::forward<Tie>(t));
}
template<class Tuple, class Ref>
constexpr auto operator<<(dier<Tuple> original, Ref&& ref) {
return make_dier(original.code, std::tuple_cat(original.refs_, std::tie(ref)));
}
template<class T, class...Refs>
T operator||(T &&t, dier<Refs...> death) {
if (!t) {
death();
}
return std::forward<T>(t);
}
}
template<class Tie = std::tuple<>>
constexpr auto die(int code = 100, Tie&& t = {}) {
return detail::make_dier(code, std::forward<Tie>(t));
}
int main(int argc, char *argv[]) {
// preconditions
argc >= 2 or die(4) << "usage: myprog <inputfile>\n";
auto input = std::ifstream(argv[1]) or die(5) << "failed to open " << std::setfill('-') << std::setw(10) << argv[1] << " and here is a hex number " << std::hex << 40;
}
This is my attempt to improve #RichardHodges self answer.
First, some library esque code:
namespace notstd {
// takes a function object
// returns a function object that calls the first function object once for each argument
template<class F>
auto foreach( F&& f ) {
return [f=std::forward<F>(f)](auto&&...args)mutable{
using discard=int[];
(void)discard{0,(void(
f(decltype(args)(args))
),0)...};
};
}
// weak version of std::apply:
template<std::size_t...Is, class F, class Tuple>
decltype(auto) apply( std::index_sequence<Is...>, F&& f, Tuple&& tup) {
return std::forward<F>(f)( std::get<Is>(std::forward<Tuple>(tup))... );
}
template<class F, class Tuple>
decltype(auto) apply(F&& f, Tuple&& tup) {
auto indexes = std::make_index_sequence< std::tuple_size< std::remove_reference_t<Tuple> >{} >{};
return apply(indexes, std::forward<F>(f), std::forward<Tuple>(tup) );
}
}
now we use it. This code is briefer due to the above:
namespace death {
namespace details {
template<class Tuple>
struct dier;
}
template<class Tuple=std::tuple<>>
details::dier<Tuple> die( int code, std::ostream& os = std::cerr, Tuple&& tuple={} ) {
return {code, os, std::forward<Tuple>(tuple)};
}
namespace details {
// a class that emits a number of references to std::cerr and then
// exits
template<class Tuple>
struct dier {
void operator()() const {
notstd::apply( notstd::foreach( [&](auto const&e){ os << e; } ), refs_ );
os << std::endl;
std::exit(code);
}
int code;
std::ostream& os;
Tuple refs_;
template<class Ref>
friend auto operator<<(dier&& original, Ref const &ref) {
return die( original.code, original.os, std::tuple_cat( std::move(original).refs_, std::tie(ref) ) );
}
template<class T>
friend T operator||(T &&t, dier&& death) {
if (!t) {
death();
}
return std::forward<T>(t);
}
};
}
}
auto die(int code = 100, std::ostream& os = std::cerr) {
return death::die(code, os);
}
Hope that helps.
Live example.
Note that all ... is eliminated except in the utility code.
#include <Windows.h>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
class CTest
{
public:
template<typename... Args>
void AddStringsToVector(const std::string &First, Args&... args);
private:
std::vector<std::string> m_stringsvec;
};
template<typename... Args>
void CTest::AddStringsToVector(const std::string &First, Args&... args)
{
m_stringsvec.push_back(First);
m_stringsvec.push_back(args...);
for (auto &i : m_stringsvec)
std::cout << i << std::endl;
}
void main()
{
CTest test;
test.AddStringsToVector("test1","test2","test3");
system("pause");
}
only works when i pass two parameters:
test.AddStringsToVector("test1","test2");
If I pass any number of parameters other then two I get an error.
For example:
test.AddStringsToVector("test1","test2","test3");
Error:
Severity Code Description Project File Line
Error C2661 'std::vector>::push_back':
no overloaded function takes 2
arguments
Recursively call the function .
void CTest::AddStringsToVector()//function to break recursion
{
}
template<typename... Args>
void CTest::AddStringsToVector(const std::string &First, Args&... args)
{
m_stringsvec.push_back(First);
AddStringsToVector(args...);
}
A non-recursive method:
class CTest
{
public:
template<typename... Args>
void AddStringsToVector(const std::string &first, const Args&... args)
{
m_stringsvec.push_back(First);
int dummy[] = { 0, (m_stringsvec.push_back(args), 0)...}; // all magic is here
(void) dummy; // Avoid unused variable warning.
for (const auto &s : m_stringsvec) {
std::cout << i << std::endl;
}
}
private:
std::vector<std::string> m_stringsvec;
};
The real stuff is there:
int dummy[] = { 0, (m_stringsvec.push_back(args), 0)...};
(foo(), 0) uses comma operator. That do the first part (the job we want) and evaluate as 0.
With variadic expansion, it becomes (m_stringsvec.push_back(args), 0)....
put the whole in initializer list to guaranty order evaluation.
In C++17, it would be even simpler with folding expression:
template<typename... Args>
void AddStringsToVector(const std::string &first, const Args&... args)
{
m_stringsvec.push_back(First);
(m_stringsvec.push_back(args), ...); // Folding expression
for (const auto &s : m_stringsvec) {
std::cout << i << std::endl;
}
}
Another non-recursive option (warning, brain compile):
struct swallow { template <typename ...T> swallow(T&& ...) noexcept { } };
class CTest
{
public:
template<typename... Args>
void AddStringsToVector(const std::string &first, const Args&... args)
{
m_stringsvec.push_back(First);
swallow{(m_stringsvec.push_back(args), 0)...};
for (const auto &s : m_stringsvec) {
std::cout << i << std::endl;
}
}
private:
std::vector<std::string> m_stringsvec;
};
#include <cstdio>
#include <string>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/lexical_cast.hpp>
struct CLASS{
template<typename T, typename ... Args>
void enqueue(T const & t, Args const & ... args){
this->concatenate(t,args ...);
}
template<typename T, typename ... Args>
void concatenate(T t, Args ... args){
boost::function<void()> f
= boost::bind(&CLASS::push_,this,
boost::bind(&CLASS::stringer<T const &,
Args const & ...>,
this,boost::ref(t),boost::ref(args)...));
}
template<typename T, typename ... Args>
std::string stringer(T const & t, Args const & ... args){
return stringer(t) + stringer(args...);
}
template <typename T>
std::string stringer(T const & t){
return boost::lexical_cast<std::string>(t);
}
void push_(std::string const & s){
std::fprintf(stderr,"%s\n",s.c_str());
}
};
int main(){
CLASS c;
c.enqueue(42,"hello",35);
// below commented enqueue fails to compile
//c.enqueue("abc", 100," for ", 42000,"sadada ", 4.3, "zzzzz\n",42,42);
return 0;
}
In the main function above, the commented line fails to compile, although the uncommented enqueue does work. I have a feeling the problem is to do with the unwinding of the variadics by the stringer function and boost::bind failing to figure out overloads or something.
How do I solve this problem, so that enqueue works for any combination of inputs?
under c++11,we cannot bind a overload function.
but there is solution under C++14:
example:
struct ulong_ip_tag{};
struct string_ip_tag{};
struct resolved_ip_tag{};
struct invalid_ip_tag{};
template<typename _Type, typename _Handler>
void handler(_Handler, _Type)
{
std::cout << "other type" << std::endl;
}
template<typename _Handler>
void handler(_Handler, resolved_ip_tag)
{
std::cout << typeid(resolved_ip_tag).name() << std::endl;
}
template<typename _Handler>
void handler(_Handler, string_ip_tag)
{
std::cout << typeid(string_ip_tag).name() << std::endl;
}
template<typename _Handler>
void handler(_Handler, ulong_ip_tag)
{
std::cout << typeid(ulong_ip_tag).name() << std::endl;
}
void test(){}
int main()
{
//auto--- under c++14
auto b = [](auto arg1,auto arg2){handler(arg1,arg2)};
std::bind(b,test,ulong_ip_tag());
}