how to refactor this class template to minimize boiler-plate code? - c++

I've recently started using boost mirror for ORM reflection so I can minimize the amount of DB-related boiler-plate code.
One kind of pattern I've run into is listed below.
Since Bar's code is going to look identical even for Baz, I was wondering, is it possible to collapse this code any further?
It would be nice if the getValues() interface would look the same, but the identical implementation could also live in Foo instead.
#include <iostream>
template< typename T >
struct Foo
{
static std::ostream& GetValues_Worker( std::ostream& os, T const& t )
{
// do boost mirror reflection stuff here
return os;
}
};
struct Bar :
public Foo<Bar>
{
// REFACTOR IF POSSIBLE: this code will always look the same - even for Baz
std::ostream&
getValues( std::ostream& os ) const
{
return GetValues_Worker( os, *this );
}
};
struct Baz :
public Foo<Baz>
{
// REFACTOR IF POSSIBLE: looks the same as Bar
std::ostream&
getValues( std::ostream& os ) const
{
return GetValues_Worker( os, *this );
}
};
int main( int argc, char* argv[] )
{
Bar b;
std::cerr << b.getValues( std::cerr ) << std::endl;
}
ANSWER
It turns out that ecatmur's answer below works in most cases. In my specific situation, I adapted his solution to my real code, it worked in 2 out of 4 cases. In the two cases where it failed to work, it was a bit beyond the scope of the Mickey-Mouse example that I gave above. The closest explanation that I could find in SO which explains the compile-time errors I was getting is probably this post. The crux of the problem appeared to be related to what was happening inside my Worker code. In the two failed cases, I was doing output streaming of the subclasses' members based on what I was getting back from runtime reflection results in boost mirror. I think this is turned out to be a case of non-deducible context. I still don't understand why the solution in those two failed cases works exactly (why using a visitor in the form of a virtual method gets around the issue). Anyhow, I stumbled upon that approach and was trying to reduce the code some more (in those 4 cases), but in two of them, I couldn't really reduce that code any more without running into the non-deducible context issue.

Bar::getValues can be moved to Foo<Bar> using a CRTP downcast:
template< typename T >
struct Foo
{
static std::ostream& GetValues_Worker( std::ostream& os, T const& t )
{
// do boost mirror reflection stuff here
return os;
}
std::ostream& getValues( std::ostream& os ) const
{
return GetValues_Worker( os, *static_cast<T const *>(this) );
}
};
At this point you might as well combine the two methods:
template< typename T >
struct Foo
{
std::ostream& getValues( std::ostream& os ) const
{
T const &t = *static_cast<T const *>(this);
// do boost mirror reflection stuff here
return os;
}
};

Related

Argument Dependent Lookup and stream operators overloading

I have a library which expose some sort of container struct in which I want to collect diverse generic type of data which might be from the same namespace of the library as well as data from the std namespace such as array or tuple or pairs.
This container has a print_all method which will invoke operator<< for all the elements in the container. Such an operator is supposed to be provided by the user of the library.
Testing the library, I am using different template parameters for T, but I do not care too much about what is being printed by the print_all method. For the test purpose I care only that an example character is being printed no matter which T is being tested. Actually, I my real code I am using Google Test Framework and the behavior of the method under test is really asserted to be the same for every data type provided.
I tried to provide both a generic version of operator<< and two specific versions of it. You can see them in between the #if directive. None of the two compilation branches compiles correctly, most likely because of some violation of the König lookup rules. But anyway what I want to do should be easily possible somehow. What am I missing?
Here is the example code:
#include <algorithm>
#include <iostream>
#include <vector>
namespace my
{
template<typename DataType>
struct Container
{
void print_all( std::ostream& os ) const
{
std::for_each(std::begin(data),
std::end(data),
[&os](const DataType& value)
{
os << value;
});
}
std::vector<DataType> data;
};
namespace test
{
struct Data
{
std::byte data[4];
};
using Array = std::array<std::byte,4>;
#if 0
template<typename T>
std::ostream& operator<<(std::ostream& os, const T& data)
{
return os << 'X';
}
#else
std::ostream& operator<<(std::ostream& os, const Data& data)
{
return os << 'X';
}
std::ostream& operator<<(std::ostream& os, const Array& data)
{
return os << 'X';
}
#endif
void run()
{
// Test with custom data
{
Container< Data> container;
container.data.resize(1);
container.print_all( std::cout );
}
// Test with std data
{
Container< Array> container;
container.data.resize(1);
container.print_all( std::cout );
}
}
} // namespace test
} // namespace my
int main()
{
my::test::run();
return 0;
}
ADL looks into the namespaces associates with the arguments.
using Array = std::array<std::byte,4>;
this type test::Array is an alias. The namespaces associated with it for the purpose of ADL is std. test is not associated with it. ADL will only look in std. You are not permitted to add operators to std; if you violate that, your program is ill-formed, no diagnostic required. ADL cannot help you, because it only helps people who own the namespace(s) associated with the arguments.
Any << you want to support in std needs to be in namespace my, defined before your print_all function.
Your code for Data looks to me like it works, I assume your question was just poorly written, as it implies os <<Data does not work. If I am wromg amd it doesn't work, it is because of some typo; ADL works fine on structs, but not on aliases. In the future, please include complete error messages when code doesn't work.

Simple types with higher meaning (C++11)

I often run into situations (in my C++/C++11 code), where I have a type that basically behaves like a built-in type (or a "basic simple" type like std::string), but that has a meaning
beyond a 32 bit number or a bunch of characters.
I didn't find anything useful on the Internet, because I don't really what terms to search for...
Examples:
I once worked on a system, where items were identified by an ID. And these IDs were std::strings (probably not the best idea in the first place, but that's a different story). What was really bad though was the fact, that these IDs were passed through the system as std::strings or as const char*s. So it was hard (impossible) to tell where in the
code base IDs were used when searching for the type. The variable names were all variations of ID(ID, id, Id) or key or just i or name or whatever. So you could not search by name either. So I'd prefer to pass those variables as type id_t.
Network ports: They are uint16_ts. But I would like to pass them as network_port_ts.
I generally used typedefs to make things a little nicer. This approach has multiple problems though:
You don't have to use the typedef. You can still pass variables around by the "raw" type (e.g. std::string instead of id_t).
If the raw type is a template, you are done with forward declaring the typedef (e.g. with a shared_ptr).
"Forward declaring" the typedef is a maintenance problem. If the raw type changes, you get to change stuff all over the place.
Another thing I tried with the network port example was writing a thin wrapper class sporting a operator uint16_t. This solved the problem with forward declarations. But then I ran
into a trap with some logging macros which used printf internally. The printfs still worked (well, compiled), but didn't print the port number, but (I think) the address of the object.
I figured with dimensions like weights or lengths Boost.Units might be worth a look (even so it appears a little "heavy"). But for the two examples above, it doesn't fit.
What is the best practice to achieve what I want (using Boost is an option)?
In short:
What I want to achieve is to pass "types with higher meaning" as its own type and not as the plain raw/low level/non-abstract type. (Kind of) like having a user defined type. Preferably without the huge overhead of writing a complete class for every type with basically identical implementations, only to be able to do what built-ins already can do.
1. Strong Typedefs
You can use BOOST_STRONG_TYPEDEF to get some convenience.
It does employ macros, and I think you get to do heterogeneous comparisons (e.g. id == "123").
There's two versions, be sure to take the one from Boost Utility.
2. flavoured_string<>
For strings you can cheat the system by using flavoured strings (inventor: R.Martinho Fernandes).
This leverages the fact that you can actually vary the traits on a std::basic_string, and create actually different tagged aliases:
#include <string>
#include <iostream>
namespace dessert {
template <typename Tag>
struct not_quite_the_same_traits : std::char_traits<char> {};
template <typename Tag>
using strong_string_alias = std::basic_string<char, not_quite_the_same_traits<Tag>>;
using vanilla_string = std::string;
using strawberry_string = strong_string_alias<struct strawberry>;
using caramel_string = strong_string_alias<struct caramel>;
using chocolate_string = strong_string_alias<struct chocolate>;
template <typename T>
struct special;
template <typename T>
using special_string = strong_string_alias<special<T>>;
std::ostream& operator<<(std::ostream& os, vanilla_string const& s) {
return os << "vanilla: " << s.data();
}
std::ostream& operator<<(std::ostream& os, strawberry_string const& s) {
return os << "strawberry: " << s.data();
}
std::ostream& operator<<(std::ostream& os, caramel_string const& s) {
return os << "caramel: " << s.data();
}
std::ostream& operator<<(std::ostream& os, chocolate_string const& s) {
return os << "chocolate: " << s.data();
}
template <typename T>
std::ostream& operator<<(std::ostream& os, special_string<T> const& s) {
return os << "special: " << s.data();
}
}
int main() {
dessert::vanilla_string vanilla = "foo";
dessert::strawberry_string strawberry = "foo";
dessert::caramel_string caramel = "foo";
dessert::chocolate_string chocolate = "foo";
std::cout << vanilla << '\n';
std::cout << strawberry << '\n';
std::cout << caramel << '\n';
std::cout << chocolate << '\n';
dessert::special_string<struct nuts> nuts = "foo";
std::cout << nuts << '\n';
}
To create an integer that's not an integer (or a string that's not a string) and cannot promote or demote to it), you can only create a new type, that merely means "write a new class". There is no way -at least on basic type- to inherit behaviour without aliasing. A new_type<int> has no arithmetic (unless you'll define it).
But you can define a
template<class Innertype, class Tag>
class new_type
{
Innertype m;
public:
template<class... A>
explicit new_type(A&&... a) :m(std::forward<A>(a)...) {}
const Innertype& as_native() const { return m; }
};
and do all the workout only once for all.
template<class T, class I>
auto make_new_type(I&& i)
{ return new_type<I,T>(std::forward<I>(i)); }
template<class A, class B, class T>
auto operator+(const new_type<A,T>& a, const new_type<B,T>& b)
{ return make_new_type<T>(a.as_native()+b.as_native()); }
....
and then
struct ID_tag;
typedef new_type<std::string,ID_tag> ID;
struct OtehrID_tag;
typedef new_type<std::string,OtehrID_tag> OtherID;
and ID oand OtherID cannot mix in expressions.
NOTE:
auto -function with unspecifyed return are standard from C++14, but GCC accepts it in C++11 as-well.
template <typename tag_t, typename value_t>
struct meaningful_value
{
typedef value_t value_type;
meaningful_value() : value() {}
explicit meaningful_value(const value_type & val) : value(val) {}
operator const value_type & () const { return value; }
protected:
value_type value;
};
typedef meaningful_value<struct ParamType1_tag, double> ParamType1;
typedef meaningful_value<struct ParamType2_tag, double> ParamType2;
This is basically what boost::quantity does, but allows for default construction; the tag struct can be declared inplace in the typedef, so declaring a new type of parameter is a single-line deal; you get to choose if you want a macro for it
(Edited to fix constructor name)

boost::type_erasure basic example doesn't build

I am testing the new boost::type_erasure. Unfortunately taking the code of the basic example as it is it doesn't build. To be more specific this example the function basic2() is giving trouble. I tried to highlight who is creating the issues and it seems that these 2 concepts are the cause
incrementable<> // error: no match for ‘operator++’ in ‘++arg’
ostreamable<> // error: no match for ‘operator<<’ in ‘out << arg
If I am not wrong these are 2 concepts are already implemented in the library; being used with int the code should really work as it is so I don't know how to fix this issue.
Has any of you guys had a similar issue and in case do you have any idea about how to fix it?
I am using gcc 4.4.7-3
I also tried the following example
class CTest{
public:
CTest(const CTest& o){}
CTest(){}
};
std::ostream& operator<<(std::ostream& o,const CTest& obj){
return o;
}
void basic2() {
CTest c;
any<
mpl::vector<
copy_constructible<>,
typeid_<>,
ostreamable<>
>
> x(c);
std::cout << c ;
}
And I have the same error. It actually points to this code in boost saying that
error: no match for ‘operator<<’ in ‘out << arg’
Below is the function that fails. I don't understand why as it needs operator<< that is already defined.
// from operators.hpp from boost type_erasure
/**
* The #ref ostreamable concept allows an #ref any to be
* written to a #c std::ostream.
*/
template<class Os = std::ostream, class T = _self>
struct ostreamable
{
static void apply(Os& out, const T& arg) { out << arg; }
};

Change the complex number output format

There is the complex<> template in C++ standard library, and it has an overloaded << operator so that it outputs complex numbers in the (real_part, im_part) format. I need to change the behavior of that operator for complex numbers so that the output format is changed to something completely different. Specifically, I need the output to be in the form real_part\tim_part. How do I do that?
There's no direct way to replace operator <<, but you do have a few options. First, you could just write your own function to print complex numbers:
template <typename T> void PrintComplex(const complex<T>& c) {
/* ... */
}
If you want to still use the nice stream syntax, then one trick you could do would be to make a wrapper class that wraps a complex and then defines its own operator << that prints it out in a different way. For example:
template <typename T> class ComplexPrinter {
public:
/* Conversion constructor allows for implicit conversions from
* complex<T> to ComplexPrinter<T>.
*/
ComplexPrinter(const complex<T>& value) : c(value) {
// Handled in initializer list
}
/* Output the complex in your own format. */
friend ostream& operator<< (ostream& out, const ComplexPrinter& cp) {
/* ... print in your own format ... */
}
private:
complex<T> c;
};
Once you have this, you could write something like
cout << ComplexPrinter<double>(myComplex) << endl;
You can make this even cleaner by writing a function like this one to wrap the object for you:
template <typename T>
ComplexPrinter<T> wrap(const complex<T>& c) {
return ComplexPrinter<T>(c);
}
This then lets you write
cout << wrap(myComplex) << endl;
Which isn't perfect, but is pretty good.
One thing to note about the above wrapper is that it has an implicit conversion constructor set up to let you convert complex<T>s to ComplexPrinter<T>s. This means that if you have a vector< complex<T> >, you can print it out using your custom code by calling
vector< complex<double> > v = /* ... */
copy (v.begin(), v.end(), ostream_iterator< ComplexPrinter<double> >(cout, " "));
On output, the implicit conversion constructor will transform your complex<double>s into the wrappers, and your custom code will do the printing for you.
If you want to be very adventurous and cast caution to the wind, you could even write the class so that it just stores a reference to the original complex, as shown here:
template <typename T> class ComplexPrinter {
public:
/* Conversion constructor allows for implicit conversions from
* complex<T> to ComplexPrinter<T>.
*/
ComplexPrinter(const complex<T>& value) : c(value) {
// Handled in initializer list
}
/* Output the complex in your own format. */
friend ostream& operator<< (ostream& out, const ComplexPrinter& cp) {
/* ... print in your own format ... */
}
private:
const complex<T>& c;
};
This completely eliminates any copying and just makes the wrapper a thin veneer around a real complex. (No pun intended). You'd have to be very careful if you did this not to pass these objects around across scope boundaries where the original objects go out of scope, but if it's what you want it might work out just great.
Hope this helps!
template<class T>
struct my_complex_format_type {
std::complex<T> const &x;
my_complex_format_type(std::complex<T> const &x) : x (x) {}
friend std::ostream& operator<<(std::ostream &out,
my_complex_format_type const &value)
{
out << "format value.x however you like";
return out;
}
};
template<class T>
my_complex_format_type<T> my_complex_format(std::complex<T> const &x) {
return x;
}
void example() {
std::cout << my_complex_format(some_complex);
}
For any specific instantiation of complex<T>, Use a strong typedef (boost has a version) and cast to that type during << calls. Override << for that type.
If you need to override << for any variation of complex<T> then life will be harder.
My answer to the same question here: c++ display complex number with i in imaginary part produces the behavior you want, at the expense of some risk of future incompatibility because it inserts a template specialization into the std:: namespace.
There is no really tidy way to do that. My suggestion would be to just ditch iostreams and write something more C-like instead. It will probably be faster to write, faster to read and faster to execute.

Implementing a no-op std::ostream

I'm looking at making a logging class which has members like Info, Error etc that can configurably output to console, file, or to nowhere.
For efficiency, I would like to avoid the overhead of formatting messages that are going to be thrown away (ie info messages when not running in a verbose mode). If I implement a custom std::streambuf that outputs to nowhere, I imagine that the std::ostream layer will still do all the formatting. Can anyone suggest a way to have a truly "null" std::ostream that avoids doing any work at all on the parameters passed to it with <<?
A swift google came up with this example which may be of use. I offer no guarantees, except that it compiles and runs :-)
#include <streambuf>
#include <ostream>
template <class cT, class traits = std::char_traits<cT> >
class basic_nullbuf: public std::basic_streambuf<cT, traits> {
typename traits::int_type overflow(typename traits::int_type c)
{
return traits::not_eof(c); // indicate success
}
};
template <class cT, class traits = std::char_traits<cT> >
class basic_onullstream: public std::basic_ostream<cT, traits> {
public:
basic_onullstream():
std::basic_ios<cT, traits>(&m_sbuf),
std::basic_ostream<cT, traits>(&m_sbuf)
{
init(&m_sbuf);
}
private:
basic_nullbuf<cT, traits> m_sbuf;
};
typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;
int main() {
onullstream os;
os << 666;
}
all, thanks for sharing the code, I just do a test, then Neil's method will still do the string formating, for example:
#include <streambuf>
#include <ostream>
#include <iostream>
using namespace std;
template <class cT, class traits = std::char_traits<cT> >
class basic_nullbuf: public std::basic_streambuf<cT, traits> {
typename traits::int_type overflow(typename traits::int_type c)
{
return traits::not_eof(c); // indicate success
}
};
template <class cT, class traits = std::char_traits<cT> >
class basic_onullstream: public std::basic_ostream<cT, traits> {
public:
basic_onullstream():
std::basic_ios<cT, traits>(&m_sbuf),
std::basic_ostream<cT, traits>(&m_sbuf)
{
init(&m_sbuf);
}
private:
basic_nullbuf<cT, traits> m_sbuf;
};
typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;
class MyClass
{
int a;
friend ostream& operator<< (ostream&, MyClass const&);
};
ostream& operator<<(ostream& out,MyClass const& b)
{
std::cout<<"call format function!!";
out << b.a;
return out;
}
int main() {
onullstream os;
MyClass obj;
os<<obj;
}
Running this program, you will find that "ostream& operator<<(ostream& out,MyClass const& b)" will be called. So, doing format on the obj will still be called. So, we still can't avoid the overhead of formatting messages.
To prevent the operator<<() invocations from doing formatting, you should know the streamtype at compile-time. This can be done either with macros or with templates.
My template solution follows.
class NullStream {
public:
void setFile() { /* no-op */ }
template<typename TPrintable>
NullStream& operator<<(TPrintable const&)
{ return *this; } /* no-op */
}
template<class TErrorStream> // add TInfoStream etc
class Logger {
public:
TErrorStream& errorStream() {
return m_errorStream;
}
private:
TErrorStream m_errorStream;
};
//usage
int main() {
Logger<std::ofstream> normal_logger; // does real output
normal_logger.errorStream().open("out.txt");
normal_logger.errorStream() << "My age is " << 19;
Logger<NullStream> null_logger; // does zero output with zero overhead
null_logger.errorStream().open("out.txt"); // no-op
null_logger.errorStream() << "My age is " << 19; // no-op
}
Since you have to do this at compile-time, it is of course quite inflexible.
For example, you cannot decide the logging level at runtime from a configuration file.
Probably you'll need more than just text formatting and message filtering. What about multithreading?
I would implement the filtering and multithreading synchronization as the responsibility of a separate class.
However, logging is a not-so-simple problem, and I would try to use existing logging solutions, instead of developing a new one.
Why not using existing logging solutions used by millions of users?
log4j, log4net, log4cxx.., to name just a few..