Copy-and-swap done through interfaces - c++

I'm trying to implement a copy+swap idiom to achieve strong-exception safety through a level of abstraction and, although the principle is clear, as it's often the case the devil is in the detail.
Say I have a class that looks like this:
class AConcreteType :
public ISomething,
public ISwappable
{
public:
// From ISwappable
void Swap( ISwappable& );
};
I can now do this within a method that only deals with ISomething:
void AClass::DoSomething( ISomething& something )
{
// say there is a function that allows me to clone 'something'
// Probably it ought to go into an auto_ptr, but for clarity:
ISomething& somethingElse( clone( something ) );
// ... so that at the end, after doing stuff with somethingElese I can do
ISwappable& swappable1 = dynamic_cast<ISwappable&>( something );
ISwappable& swappable2 = dynamic_cast<ISwappable&>( somethingElse );
// ... I may want to check that the concrete types behind the interface are
// actually the same too with something like typeid, but I'll leave that out for clarity
swappable1.Swap( swappable2 );
}
where
void AConcreteType::Swap( ISwappable& swappable )
{
AConcreteType& somethingConcrete = dynamic_cast<AConcreteType&>(swappable);
std::swap( *this, somethingConcrete );
}
This all works, as all the dynamic_casts are on references, which is an operation that throws when the type is not supported; this leaves my objects in a good state as the swap doesn't happen until the very end. But what I'm not comfortable with is the fact that the call swappable1.Swap(swappable2) can still throw (via the same dynamic_cast mechanism), and that would be counter-intuitive for the user of Swap as he would probably not expect anything to throw at that point.
An alternative I thought of was to template ISwappable so as to do away with the dynamic_cast inside the implementation of Swap:
template< typename T >
class ISwappable
{
public:
virtual void Swap( T& ) = 0;
};
so that its implementation is simply
class AConcreteType :
public ISomething,
public ISwappable<AConcreteType>
{
void Swap( AConcreteType& act ) { std::swap( *this, act ); }
};
This allows the Swap call to be non-throw (and allows me to guarantee that the two objects are actually swappable at compile-time), but the problem now is that I have to deal with a concrete type inside DoSomething, but I don't have access to AConcreteType inside that function.
Any ideas?

C++ isn't particularly geared toward inheritance based interfaces. For example, you're implementing a function that takes an ISomething, but it also expects the object to be an ISwappable. Languages geared toward using interfaces like this usually have a direct way to express requirements for multiple interfaces on a single type.
Instead it's probably better in C++ to use templates and then express requirements on those template parameters when necessary. Static assertions and type traits are a pretty simple and readable way of doing this in C++.
template<typename T,typename Interface>
struct implements {
static constexpr bool value = std::is_base_of<Interface,T>::value;
}
template<typename T>
void AClass::DoSomething(T &something ) {
static_assert(implements<T,ISomething>::value, "requires ISomething");
static_assert(implements<T,ISwappable<T>>::value, "requires ISwappable");
T somethingElse = clone(something);
something.Swap(somethingElse);
}
You might also want to move away from using inheritance for interfaces altogether. You can usually get the static type checking on your classes via static_asserts and type traits without inheritance:
template<typename T>
struct is_swappable { static constexpr bool value = ... };
class AConcreteType {
...
};
static_assert(is_swappable<AConcreteType>,"...");
template<typename T>
void AClass::DoSomething(T &something ) {
static_assert(is_something<T>::value, "requires something");
static_assert(is_swappable<T>::value, "requires swappable");

If you ask me, the idea of a ISwappable is already "ill-posed" since you cannot swap abstract types into each other without consequences... What you can swap safely are addresses of interfaces (pointers):
std::unique_ptr<ISomething> tI1(new AConcreteType(1)), tI2(new BConcreteType(2));
std::cout << tI1->IdentifyYourSelf() << std::endl; // -> prints "1"
std::cout << tI2->IdentifyYourSelf() << std::endl; // -> prints "2"
tI1.swap(tI2);
// contents are swapped now
std::cout << tI1->IdentifyYourSelf() << std::endl; // -> prints "2"
std::cout << tI2->IdentifyYourSelf() << std::endl; // -> prints "1"

Related

Can static polymorphism (templates) be used despite type erasure?

Having returned relatively recently to C++ after decades of Java, I am currently struggling with a template-based approach to data conversion for instances where type erasure has been applied. Please bear with me, my nomenclature may still be off for C++-natives.
This is what I am trying to achieve:
Implement dynamic variables which are able to hold essentially any value type
Access the content of those variables using various other representations (string, ints, binary, ...)
Be able to hold variable instances in containers, independent of their value type
Convert between variable value and representation using conversion functions
Be able to introduce new representations just by providing new conversion functions
Constraints: use only C++-11 features if possible, no use of libraries like boost::any etc.
A rough sketch of this might look like this:
#include <iostream>
#include <vector>
void convert(const std::string &f, std::string &t) { t = f; }
void convert(const int &f, std::string &t) { t = std::to_string(f); }
void convert(const std::string &f, int &t) { t = std::stoi(f); }
void convert(const int &f, int &t) { t = f; }
struct Variable {
virtual void get(int &i) = 0;
virtual void get(std::string &s) = 0;
};
template <typename T> struct VariableImpl : Variable {
T value;
VariableImpl(const T &v) : value{v} {};
void get(int &i) { convert(value, i); };
void get(std::string &s) { convert(value, s); };
};
int main() {
VariableImpl<int> v1{42};
VariableImpl<std::string> v2{"1234"};
std::vector<Variable *> vars{&v1, &v2};
for (auto &v : vars) {
int i;
v->get(i);
std::string s;
v->get(s);
std::cout << "int representation: " << i <<
", string representation: " << s << std::endl;
}
return 0;
}
The code does what it is supposed to do, but obvoiusly I would like to get rid of Variable::get(int/std::string/...) and instead template them, because otherwise every new representation requires a definition and an implementation with the latter being exactly the same as all the others.
I've played with various approaches so far, like virtual templated, methods, applying the CRDT with intermediate type, various forms of wrappers, yet in all of them I get bitten by the erased value type of VariableImpl. On one hand, I think there might not be a solution, because after type erasure, the compiler cannot possibly know what templated getters and converter calls it must generate. On the other hand I think i might be missing something really essential here and there should be a solution despite the constraints mentioned above.
This is a classical double dispatch problem. The usual solution to this problem is to have some kind of dispatcher class with multiple implementations of the function you want to dispatch (get in your case). This is called the visitor pattern. The well-known drawback of it is the dependency cycle it creates (each class in the hierarchy depends on all other classes in the hierarchy). Thus there's a need to revisit it each time a new type is added. No amount of template wizardry eliminates it.
You don't have a specialised Visitor class, your Variable serves as a Visitor of itself, but this is a minor detail.
Since you don't like this solution, there is another one. It uses a registry of functions populated at run time and keyed on type identification of their arguments. This is sometimes called "Acyclic Visitor".
Here's a half-baked C++11-friendly implementation for your case.
#include <map>
#include <vector>
#include <typeinfo>
#include <typeindex>
#include <utility>
#include <functional>
#include <string>
#include <stdexcept>
struct Variable
{
virtual void convertValue(Variable& to) const = 0;
virtual ~Variable() {};
virtual std::type_index getTypeIdx() const = 0;
template <typename K> K get() const;
static std::map<std::pair<std::type_index, std::type_index>,
std::function<void(const Variable&, Variable&)>>
conversionMap;
template <typename T, typename K>
static void registerConversion(K (*fn)(const T&));
};
template <typename T>
struct VariableImpl : Variable
{
T value;
VariableImpl(const T &v) : value{v} {};
VariableImpl() : value{} {}; // this is needed for a declaration of
// `VariableImpl<K> below
// It can be avoided but it is
// a story for another day
void convertValue(Variable& to) const override
{
auto typeIdxFrom = getTypeIdx();
auto typeIdxTo = to.getTypeIdx();
if (typeIdxFrom == typeIdxTo) // no conversion needed
{
dynamic_cast<VariableImpl<T>&>(to).value = value;
}
else
{
auto fcnIter = conversionMap.find({getTypeIdx(), to.getTypeIdx()});
if (fcnIter != conversionMap.end())
{
fcnIter->second(*this, to);
}
else
throw std::logic_error("no conversion");
}
}
std::type_index getTypeIdx() const override
{
return std::type_index(typeid(T));
}
};
template <typename K> K Variable::get() const
{
VariableImpl<K> vk;
convertValue(vk);
return vk.value;
}
template <typename T, typename K>
void Variable::registerConversion(K (*fn)(const T&))
{
// add a mutex if you ever spread this over multiple threads
conversionMap[{std::type_index(typeid(T)), std::type_index(typeid(K))}] =
[fn](const Variable& from, Variable& to) {
dynamic_cast<VariableImpl<K>&>(to).value =
fn(dynamic_cast<const VariableImpl<T>&>(from).value);
};
}
Now of course you need to call registerConversion e.g. at the beginning of main and pass it each conversion function.
Variable::registerConversion(int_to_string);
Variable::registerConversion(string_to_int);
This is not ideal, but hardly anything is ever ideal.
Having said all that, I would recommend you revisit your design. Do you really need all these conversions? Why not pick one representation and stick with it?
Implement dynamic variables which are able to hold essentially any value type
Be able to hold variable instances in containers, independent of their value type
These two requirements are quite challenging on its own. The class templates don't really encourage inheritance, and you already did the right thing to hold what you asked for: introduced a common base class for the class template, which you can later refer to in order to store pointers of the said type in a collection.
Access the content of those variables using various other representations (string, ints, binary, ...)
Be able to introduce new representations just by providing new conversion functions
This is where it breaks. Function templates assume common implementation for different types, while inheritance assumes different implementation for the same types.
You goal is to introduce different implementation for different types, and in order to make your requirements viable you have to switch to one of those two options instead (or put up with a number of functions for each case which you have already introduced yourself)
Edit:
One of the strategies you may employ to enforce inheritance approach is generalisation of the arguments to the extent where they can be used interchangeably by the abstract interface. E.g. you may wrap the converting arguments inside of a union like this:
struct Variable {
struct converter_type {
enum { INT, STRING } type;
union {
int* m_int;
std::string* m_string;
};
};
virtual void get(converter_type& var) = 0;
virtual ~Variable() = default;
};
And then take whatever part of it inside of the implementation:
void get(converter_type& var) override {
switch (var.type) {
case converter_type::INT:
convert(value, var.m_int);
break;
case converter_type::STRING:
convert(value, var.m_string);
break;
}
}
To be honest I don't think this is a less verbose approach compared to just having a number of functions for each type combination, but i think you got the idea that you can just wrap your arguments somehow to cement the abstract class interface.
Implement std::any. It is similar to boost::any.
Create a conversion dispatcher based off typeids. Store your any alongside the conversion dispatcher.
"new conversion functions" have to be passed to the dispatcher.
When asked to convert to a type, pass that typeid to the dispatcher.
So we start with these 3 types:
using any = std::any; // implement this
using converter = std::function<any(any const&)>;
using convert_table = std::map<std::type_index, converter>;
using convert_lookup = convert_table(*)();
template<class T>
convert_table& lookup_convert_table() {
static convert_table t;
return t;
}
struct converter_any: any {
template<class T,
typename std::enable_if<
!std::is_same<typename std::decay<T>::type, converter_any>::value, bool
>::type = true
>
converter_any( T&& t ):
any(std::forward<T>(t)),
table(&lookup_convert_table<typename std::decay<T>::type>())
{}
converter_any(converter_any const&)=default;
converter_any(converter_any &&)=default;
converter_any& operator=(converter_any const&)=default;
converter_any& operator=(converter_any&&)=default;
~converter_any()=default;
converter_any()=default;
convert_table const* table = nullptr;
template<class U>
U convert_to() const {
if (!table)
throw 1; // make a better exception than int
auto it = table->find(typeid(U));
if (it == table->end())
throw 2; // make a better exception than int
any const& self = *this;
return any_cast<U>((it->second)(self));
}
};
template<class Dest, class Src>
bool add_converter_to_table( Dest(*f)(Src const&) ) {
lookup_convert_table<Src>()[typeid(Dest)] = [f](any const& s)->any {
Src src = std::any_cast<Src>(s);
auto r = f(src);
return r;
};
return true;
}
now your code looks like:
const bool bStringRegistered =
add_converter_to_table(+[](std::string const& f)->std::string{ return f; })
&& add_converter_to_table(+[](std::string const& f)->int{ return std::stoi(f); });
const bool bIntRegistered =
add_converter_to_table(+[](int const& i)->int{ return i; })
&& add_converter_to_table(+[](int const& i)->std::string{ return std::to_string(i); });
int main() {
converter_any v1{42};
converter_any v2{std::string("1234")};
std::vector<converter_any> vars{v1, v2}; // copies!
for (auto &v : vars) {
int i = v.convert_to<int>();
std::string s = v.convert_to<std::string>();
std::cout << "int representation: " << i <<
", string representation: " << s << std::endl;
}
}
live example.
...
Ok, what did I do?
I used any to be a smart void* that can store anything. Rewriting this is a bad idea, use someone else's implementation.
Then, I augmented it with a manually written virtual function table. Which table I add is determined by the constructor of my converter_any; here, I know the type stored, so I can store the right table.
Typically when using this technique, I'd know what functions are in there. For your implementation we do not; so the table is a map from the type id of the destination, to a conversion function.
The conversion function takes anys and returns anys -- again, don't repeat this work. And now it has a fixed signature.
To add support for a type, you independently register conversion functions. Here, my conversion function registration helper deduces the from type (to determine which table to register it in) and the destination type (to determine which entry in the table), and then automatically writes the any boxing/unboxing code for you.
...
At a higher level, what I'm doing is writing my own type erasure and object model. C++ has enough power that you can write your own object models, and when you want features that the default object model doesn't solve, well, roll a new object model.
Second, I'm using value types. A Java programmer isn't used to value types having polymorphic behavior, but much of C++ works much better if you write your code using value types.
So my converter_any is a polymorphic value type. You can store copies of them in vectors etc, and it just works.

Ensure class methods with C++20 concepts

I love the feature of Interfaces in Java, and was looking forward to the new C++20 standart, introducing concepts.
On a current project i will have multiple implementations for the same thing. The rest of the code should be unaffected by that and handel them all in a general "one fits all" way. Further, to help other people coding there own implementation of this exchangeable part, i would like to have a central place for the documentation, describing all needed parts.
I tried to get this working for some time now, but i keep one struggeling with the C++20 concepts. Since nothing really worked i discribe what i would like to have with a small example:
/* Should have a element type, like float, int, double, std::size_t,... */
template <typename Class>
concept HasElementType = requires {
typename Class::Element;
};
/* Central place for the documentation: in the concept.
* Since all relevant parts should be listed here, they can be documentated.
*/
template < typename Class, typename T>
concept HasFunctions = requires {
Class::Class(int); /* has constructor with int */
T Class::field; /* has field with name "field" of type T */
int Class::foo(T); /* has method foo, taking T, returning int */
T Class::bar(int); /* has method bar, taking int, returning T */
void Class::foobar(); /* has method foobar, taking void, returnung void */
};
/* put both togetter */
template <typename Cls>
concept MyInterface = HasElementType<Cls> && HasFunctions<Cls,typename Cls::Element>;
The above concept MyInterface should than ensure, that calling the function below via my_function<MyObject>() should work properly for different implementations MyObject ∈ {Implementaion1, Implementaion2,...}.
/* Some example function */
template<MyInterface MyObejct>
void my_function(){
using T = MyObejct::Element;
T t = 5;
MyObejct myObject(1);
T field = myObject.field;
int foo = myObject.foo(t);
T bar = myObject.bar(1);
myObject.foobar();
}
I have 3 questions regarding this:
Is it possible with concepts, to accomplish that?
Is this in a somewhat clean look possible? Since it should increase the readability via accessible documentation, it would not be usefull if the code for the concept is barely readable.
Are concepts in generall the right approche, or are there other/better ways to accomplish that?
Thanks, moro
You haved asked multiple things, so I answer one by one. First your "HasElement" concept.
Here you can see how it works:
#include <iostream>
#include <type_traits>
class AWithStaticElement{
public:
static int Element;
};
int AWithStaticElement::Element = 12;
class AWithInstanceElement{
public:
int Element;
};
class AWithElementType{
public:
using Element = int;
};
class AWithoutElement{
};
template<typename T>
requires std::is_member_pointer_v<decltype(&T::Element)>
void Foo(T t)
{
std::cout << "Has instance Element " << t.Element << "\n";
}
template<typename T>
requires std::is_pointer_v<decltype(&T::Element)>
void Foo(T t)
{
std::cout << "Has static Element " << t.Element << "\n";
}
template<typename T>
requires requires (T t) { typename T::Element; }
void Foo(T t)
{
std::cout << "Has Element type\n";
}
template<typename... T>
void Foo(T&&... t)
{
std::cout << "Has no Element!\n";
}
int main()
{
Foo(AWithStaticElement{});
Foo(AWithInstanceElement{});
Foo(AWithElementType{});
Foo(AWithoutElement{});
}
With concepts you can basically give a set of requirements a name. If a concepts is long you don't need to repeat it all the time.
You have a plausible idea, but that's just not the syntax for requires-expressions. You want something like
template < typename Class >
concept HasFunctions = requires(Class c, Class::Element e) {
Class(1); // don't use a null pointer constant here!
{ c.field } -> std::same_as<decltype(e)>;
{ c.foo(e) } -> std::same_as<int>;
{ c.bar(1) } -> std::same_as<decltype(e)>;
c.foobar();
};
Note that there's no need to test Class::Element separately: if that type doesn't exist, then the atomic constraint simply evaluates to false as desired.
This isn't quite as strict as your phrasing suggests; it's sufficient that the class be constructible from an int (possibly via implicit conversions, default arguments, constructor templates, etc.), for example, and it ignores the return type of foobar entirely. However, as is rapidly becoming common advice for constraint authors, why do you care if foobar returns something? If you expect it to be void, you're not going to do much with the return value anyway. It's generally superior to require the interface that you will use (e.g., that you will pass an int here and ignore a value there) rather than trying to describe the implementation of the type in question. Accordingly, you might consider relaxing the std::same_as as well, perhaps with std::convertible_to.

Prefer Virtuals or Templates?

Suppose you're writing the base for multiple classes. When should you make the base class have all of the dependent operations be virtual and when should the class take a template argument which is a class with the traits necessary?
e.g.
class base
{
public:
virtual void do_run() = 0;
void general_do_run()
{
// general stuff
// then
do_run();
}
};
class child: public base
{
public:
void do_run() override {}
};
vs
template<class traits>
class base
{
public:
void general_do_run()
{
traits::do_run();
}
};
struct child_traits
{
void do_run() { }
};
class child: public base<child_traits>
{
};
I've noticed that the STL seldom uses virtuals (I assume because of the overhead).
In the virtual case I can write:
std::vector<std::unique_ptr<base>>
And I can use this to store multiple different derived classes.
In the template case there is no such straightforward way to store heterogeneous derived classes in a container and do anything useful with them. You'd have to use something like this:
std::vector<std::variant<child, child2, child3>>
Which is possible, but probably consumes more space, is less familiar to most C++ users, and is not at all flexible if someone else wants to add their own derived type without modifying the vector type.
Use virtual for runtime polymorphism. Use templates or other techniques for static (compile-time) polymorphism.
In addition to the answer from John:
Storing different types to a single vector and the potential higher memory consumption by using std::variant can be overcome by using a variant of pointer types like
std::vector< std::unique_ptr<A>, std::unique_ptr<B> >
I see a very big advantage on independent types and std::variant in the fact that we don't need a common base class. Even on heterogeneous classes we can store and do something with the elements. Even if they don't have any common base class or even they do not have a common interface at all!
struct A
{
void Do() { std::cout << "A::Do" << std::endl; }
};
struct B
{
void Do() { std::cout << "B::Do" << std::endl; }
void Foo() { std::cout << "B::Foo" << std::endl; }
};
struct C
{
void Foo() { std::cout << "C::Foo" << std::endl; }
};
int main()
{
using VAR_T = std::variant< std::unique_ptr<A>, std::unique_ptr<B> >;
std::vector<VAR_T> v;
v.emplace_back( std::make_unique<A>() );
v.emplace_back( std::make_unique<B>() );
for ( auto& el: v ) { std::visit( []( auto& el ){ el->Do(); }, el ); }
// You can combine also a vector to other unrelated types which is impossible
// in case of using virtual functions which needs a common base class.
using VAR2_T = std::variant< std::unique_ptr<B>, std::unique_ptr<C> >;
std::vector<VAR2_T> v2;
v2.emplace_back( std::make_unique<B>() );
v2.emplace_back( std::make_unique<C>() );
for ( auto& el: v2 ) { std::visit( []( auto& el ){ el->Foo(); }, el ); }
// and even if some class did not provide the functionality, we can deal with it:
// -> here we try to call Do which is only in type B!
for ( auto& el: v2 ) { std::visit(
[]( auto& el )
{
if constexpr ( requires { el->Do();} )
{
el->Do();
}
else
{
std::cout << "Element did not provide function!" << std::endl;
}
}
, el ); }
}
The argument that "feature xy is less familiar to most C++ users" is a common problem with all kind of domains. If you never had seen a hammer, it might be valid to use a stone to drive the nail. Best fit designs can only be done, if we know the toolset and how to use it. And education of teams is the best investment a tec company can do.
Back to the question what to prefer:
As always it depends on the algorithm you have to implement. If run time polymorphism is fine and fits, use it. If you can't, only as example cause of non common base class, you can drive with std::variant and std::visit.
And for all approaches CRTP comes into play to generate mixins in all its variants.
In programming in general, there is no general "x is always better as y" rule. Designs must fit! In maintainability, resource usage ( memory, time ) usability ...

What is the preferred way to store one or no object in c++?

In the spirit of "choose your containers wisely", I am interested in what is the best way to store either exactly one or no object, for example as a member in a class. This could be the case, e.g., if the object being held is expensive to calculate and should be cached in some way (or any other type of "late" creation).
The obvious candidates are std::vector and std::unique_ptr, for example:
class object_t;
class foo_t {
std::unique_ptr<object_t> m_cache;
public:
object_t getObject() {
if( not m_cache ) {
m_cache.reset(new object_t()); // object creation is expensive
}
return object_t(*m_cache);
}
};
and similarly with vector (or almost any other container):
class object_t;
class foo_t {
std::vector<object_t> m_cache;
public:
object_t getObject() {
if( m_cache.empty() ) {
m_cache.push_back(object_t()); // object creation is expensive
}
return m_cache.front();
}
};
Of course, there is still the possibility to have some boolean variable, which holds the state of the object:
class object_t;
class foo_t {
bool cache_healthy;
object_t m_cache;
public:
foo_t() : cache_healthy(false), m_cache() {}
object_t getObject() {
if( not cache_healthy ) {
m_cache = object_t();
cache_healthy = true;
}
return m_cache;
}
/* do other things that might set cache_healthy to false. */
};
From the three examples, I like the last one the less, because it either creates the object twice, or, if I change object_t to have a "cheap" / incomplete constructor, might return a invalid object.
The solution with the vector I dislike more semantically, because a vector (or any other container type) might give the impression that there might be more than just one object.
Now thinking of it again, I think I like the pointer solution most, however, still am not entirely happy with it and would like to hear if you know of any solution that is the most elegant in this case.
The "obvious" solution is using boost::optional or (in C++17) std::optional.
An implementation of something like this could look like the following:
template <typename T>
class optional
{
public:
optional() : m_isset(false) {}
template <typename ...Args>
optional(Args... args) {
m_isset = true;
new (&m_data[0]) optional { args... };
}
// overload operator-> and operator* by reinterpret_casting m_data, throwing exceptions if isset == false
private:
bool m_isset;
char m_data[sizeof(T)];
}
The disadvantages of your solutions are unneeded heap allocation in 1 and 2 and reliance on a copy in 3.

static if in plain c++?

Problem in short:
How could one implement static if functionality, proposed in c++11, in plain c++ ?
History and original problem:
Recently I came up with a problem like this. I need a class Sender with an interface like
class Sender
{
void sendMessage( ... );
void sendRequest( ... );
void sendFile( ... );
// lots of different send methods, not important actually
}
In some cases I will need to create a DoubleSender, i.e. an instance of this class, which would call its methods twice, i.e. when calling, let's say, a sendMessage(...) method, the same message has to be sent twice.
My solutions:
First approach:
Have an isDouble member, and in the end of each method call make a check
sendMessage(...) { ... if( isDouble ) { sendMessage( ... ); }
Well, I don't want this, because actually I will need double posting very recently, and this part of code in time-critical section will be 98% passive.
Second approach:
Inherit a class DoubleSender from Sender, and implement its methods like:
void DoubleSender::sendMessage( ... )
{
Sender::sendMessage(...);
Sender::sendMessage(...);
}
Well, this is acceptable, but takes much space of unpleasant code (really much, because there are lots of different send.. methods.
Third approach:
Imagine that I am using c++11 :). Then I can make this class generic and produce the necessary part of code according to tempalte argument using static if:
enum SenderType { Single, Double };
template<SenderType T>
class Sender
{
void sendMessage(...)
{
// do stuff
static if ( T == Single )
{
sendMessage(...);
}
}
};
This is shorter, easier to read than previous solutions, does not generate additional code and... it's c++11, which I unfortunately cannot use in my work.
So, here is where I came to my question - how can I implement static if analog in c++ ? Also, I would appreciate any other suggestions about how to solve my original problem.
Thanks in advance.
Quoting #JohannesSchaubLitb
with my static_if that works on gcc one can do it :)
in some limited fashion
(see also here)
This trick involves a specific GCC interpretation of the specs on Lambdas in C++11. As such, it will (likely) become a defect report against the standard. This will lead to the trick no longer working in more recent version of GCC (it already doesn't work in 4.7).
See the comment thread below for some more details from Johanness
http://ideone.com/KytVv:
#include <iostream>
namespace detail {
template<bool C>
struct call_if { template<typename F> void operator<<(F) { } };
template<>
struct call_if<true> {
template<typename F>
void operator<<(F f) { f(); }
};
}
#define static_if(cond) detail::call_if<cond>() << [&]
template<bool C, typename T>
void f(T t) {
static_if(C) {
t.foo();
};
}
int main() {
f<false>(42);
}
Why not make the send implementation a policy of the sender class and use CRTP:
template<class Derived>
class SingleSenderPolicy
{
public:
template< class memFunc >
void callWrapperImpl(memFunc f, ...)
{
static_cast<Derived *>(this)->f(...);
}
};
template< class Derived >
class DoubleSenderPolicy
{
public:
template< class memFunc >
void callWrapperImpl(memFunc f, ...)
{
static_cast<Derived *>(this)->f(...);
static_cast<Derived *>(this)->f(...);
}
};
template< class SendPolicy>
class Sender : public SendPolicy< Sender >
{
public:
void sendMessage( ... )
{
// call the policy to do the sending, passing in a member function that
// acutally performs the action
callWrapperImpl( &Sender::sendMessageImpl, ... );
}
void doSomethingElse( ... )
{
callWrapperImpl( &Sender::doSomethingElseImpl, ... );
}
protected:
void sendMessageImpl(... )
{
// Do the sending here
}
void doSomethingElseImpl(... )
{
// Do the sending here
}
};
The public sendXXX functions in you class simply forward to the call wrapper, passing in a member function that implements the real functionality. This member function will be called according to the SendPolicy of the class. CRTP saves the use of bind to wrap the arguments and this pointer up with the member function to call.
With one function it doesn't really cut down on the amount of code, but if you have a lot of calls it could help.
Note: This code is a skeleton to provide a possible solution, it has not been compiled.
Note: Sender<DoubleSenderPolicy> and Sender<SingleSenderPolicy> are completely different types and do not share a dynamic inheritance relationship.
Most compilers do constant folding and dead code removal, so if you write a regular if statement like this:
enum SenderType { Single, Double };
template<SenderType T>
class Sender
{
void sendMessage(...)
{
// do stuff
if ( T == Single )
{
sendMessage(...);
}
}
};
The if branch will get removed when the code is generated.
The need for static if is when the statements would cause a compiler error. So say you had something like this(its somewhat psuedo code):
static if (it == random_access_iterator)
{
it += n;
}
Since you can't call += on non-random access iterators, then the code would always fail to compile with a regular if statement, even with dead code removal. Because the compiler still will check the syntax for before removing the code. When using static if the compiler will skip checking the syntax if the condition is not true.
std::string a("hello world");
// bool a = true;
if(std::is_same<std::string, decltype(a)>::value) {
std::string &la = *(std::string*)&a;
std::cout << "std::string " << la.c_str() << std::endl;
} else {
bool &la = *(bool*)&a;
std::cout << "other type" << std::endl;
}