c++ - Friend a template function and avoid virtual functions/abstract bases -


i want befriend function template , want restrict template type as possible.

below snippet larger hierarchy such t in template <class t> void play(t&); can of form t, or t<u>. in case of t<u>, means t class template, befriend function specialized t<u>.

the expected behavior snippet below successful compilation/linking/execution without producing output this should not printed.

#include <iostream>  enum class genre { rock = 111, pop = 999 };  /* global interface: */ template <class t> void play(t&);  template <genre genre> class song {     /* befriend own player */     template <class t> friend void play(song<genre>&); private:     int v = int(genre); };  /* desired function resolution: */ template <genre genre> void play(song<genre>& d) {      std::cout << "genre: " << d.v << std::endl;  }  template <class t> void play(t& d) {     std::cout << "this should not printed" << std::endl; }  /* these 2 functions not desired tried... */ template<> inline void play(song<genre::pop>& d) { play<genre::pop>(d); }  template<> inline void play(song<genre::rock>& d) { play<genre::rock>(d); }  int main(int argc, char *argv[]) {     song<genre::pop> s;     song<genre::rock> p;     play<decltype(s)>(s);       play(s);     play(p);     return 0; } 

you have 2 issues here identify: friend declaration picking wrong function , 2 "not desired" functions recursively call themselves.

to fix first, need tell compiler play function template before starts looking @ song class:

/* global interface: */ //need forward declare song template class template <genre genre> class song;  //forward declare version of play templated on genre template <genre genre>  void play(song<genre>&);  //keep version had template <typename t> void play(t&);  template <genre genre> class song {     /* befriend own player */     //now picks correct function     friend void play <> (song<genre>&); private:     int v = int(genre); }; 

for forwarding functions, need make them full specializations of template <typename t> play(t&> version:

template <>  void play<song<genre::pop>> (song<genre::pop>& d) { play(d); }  template <>  void play<song<genre::rock>> (song<genre::rock>& d) { play(d); } 

an alternative make type trait checking if have passed in song, enable/disable function sfinae:

template <class t> struct is_song : std::false_type {};  template <genre genre> struct is_song<song<genre>> : std::true_type {};  template <typename t, std::enable_if_t<is_song<t>::value>* = nullptr>  void play (t& d) { play(d); }  template <typename t, std::enable_if_t<!is_song<t>::value>* = nullptr> void play(t& d) {     std::cout << "this should not printed" << std::endl; } 

now works! demo


Popular posts from this blog

c# - ODP.NET Oracle.ManagedDataAccess causes ORA-12537 network session end of file -

matlab - Compression and Decompression of ECG Signal using HUFFMAN ALGORITHM -

utf 8 - split utf-8 string into bytes in python -