Static duck in C ++

C ++ has a kind of duck typing of types defined by template parameters. We don’t know what the DUCK1 and DUCK2 types will be, but as long as they can quack() , it will compile and run:

 template <class DUCK1, class DUCK2> void let_them_quack(DUCK1* donald, DUCK2* daisy){ donald->quack(); daisy->quack(); } 

But it is a little inconvenient to write. When I am completely uninterested in what actual types DUCK1 and DUCK2 most likely want to fully use the idea of ​​duck text input, then I would like to have something similar to something more than the above:

  • I would like to omit the list of template options, which is repetitive and basically meaningless (just imagine what would happen if there are 7 ducks ...)
  • I would like to make it somewhat more explicit that types are never used and that this only matters for the interface.
  • I would like to have an annotation / interface check. It’s somehow clear which interface is expected for the type. (This, however, contrasts slightly with duck typing.)

Does C ++ offer any functions to achieve one or more of the three ideas?

(I know that virtual inheritance is the method of choice in most cases for implementing such patterns, but this is specifically about the case of static polymorphism.)

+7
c ++ c ++ 11 templates duck-typing
source share
5 answers

Regarding questions 1 and 2: since C ++ 14 you can omit the explicit template <typename ... and use auto , but only in lambdas:

 auto let_them_quack = [] (auto & donald, auto & daisy){ donald.quack(); daisy.quack(); }; 

(yes, I prefer pointers to links). GCC allows you to do this in ordinary functions as an extension.

In question 3, what are you talking about are called concepts. They existed in C ++ for a long time, but only as a documentary term. TS Concepts is now running, letting you write something like

 template<typename T> concept bool Quackable = requires(T a) { a.quack(); }; void let_them_quack (Quackable & donald, Quackable & daisy); 

Please note that this is not C ++ yet, but only a technical specification. GCC 6.1 already seems to support it. Implementations of concepts and restrictions are possible using the current C ++; You can find it in boost .

+10
source share

I would like to skip writing a list of template options, which is repeated and basically pointless (imagine what would happen if there are 7 ducks ...)

To do this, you can use variable templates and do something like the following:

 template<typename DUCK> void let_them_quack(DUCK &&d) { d.quack(); } template<typename DUCK, typename... Args> void let_them_quack(DUCK &&d, Args&& ...args) { d.quack(); let_them_quack(std::forward<Args>(args)...); } 

Live demo

+5
source share

# 2 and # 3 seem to take care that the code will not compile and throw a compilation error if these classes do not implement the interface. You can also make it formal:

 class duck { public: virtual void quack()=0; }; 

Then declare the parameters of this function by pointing to the duck. Your classes will need to inherit from this class, making the requirements for let_them_quack() crystal clear.

As for No. 1, variation patterns can take care of this.

 void let_them_quack() { } template <typename ...Args> void let_them_quack(duck* first_duck, Args && ...args) { first_duck->quack(); let_them_quack(std::forward<Args>(args)...); } 
+1
source share

You can make it more understandable with the concept (not yet standard, but very close):

http://melpon.org/wandbox/permlink/Vjy2U6BPbsTuSK3u

 #include <iostream> template<typename T>concept bool ItQuacks(){ return requires (T a) { { a.quack() } -> void; }; } void let_them_quack2(ItQuacks* donald, ItQuacks* daisy){ donald->quack(); daisy->quack(); } struct DisneyDuck { void quack(){ std::cout << "Quack!";} }; struct RegularDuck { void quack(){ std::cout << "Quack2!";} }; struct Wolf { void woof(){ std::cout << "Woof!";} }; int main() { DisneyDuck q1, q2; let_them_quack2(&q1, &q2); RegularDuck q3, q4; let_them_quack2(&q3, &q4); //Wolf w1, w2; //let_them_quack2(&w1, &w2); // ERROR: constraints not satisfied } 

exit:

  Quack!Quack!Quack2!Quack2! 

As you can see, you can: omit writing a template parameter list , ItQuacks is pretty explicit, so types are never used and that it only the interface that matters . This I'd like to have sort of an interface annotation/check. also holds, using the concept will also give you the meaning of an error message.

+1
source share

We only need to write one version of the function:

 #include <utility> template<typename... Quackers> void let_them_quack(Quackers&& ...quackers) { using expand = int[]; void(expand { 0, (std::forward<Quackers>(quackers).quack(), 0)... }); } struct Duck { void quack() {} }; int main() { Duck a, b, c; let_them_quack(a, b, c, Duck()); } 
0
source share

All Articles