3

How to make template class Collection<K,T> receive a function T - that can either has signature T(K) or T(K,int) - as template argument, then conditionally compile base on the signature of the function?

Here is the existing code that can receive 1 signature : Collection<K,HashFunction(K)>.

template<typename AA> using HashFunction= HashStruct& (*)(AA );
/** This class is currently used in so many places in codebase. */
template<class K,HashFunction<K> T> class Collection{
    void testCase(){
        K k=K();
        HashStruct& hh= T(k);                     /*Collection1*/
        //.... something complex ...
    }
};

I want it to also support Collection<K,HashFunction(K,int)>.

template<class K,HashFunction<K> T /* ??? */> class Collection{
    int indexHash=1245323;
    void testCase(){
        K k=K();
        if(T receive 2 parameter){        // ???
             HashStruct& hh=T(k,this->indexHash);  /*Collection2*/   // ???
               //^ This is the heart of what I really want to achieve.
               //.... something complex (same) ...
        }else{
             HashStruct& hh=T(k);                  /*Collection1*/
               //.... something complex (same) ... 
        }
    }
};

Do I have no choice but to create 2 different classes : Collection1 & Collection2?
Answer that need more than c++11 is ok but less preferable.

I feel that it might be solvable by using "default parameter" trick.

max66
  • 65,235
  • 10
  • 71
  • 111
javaLover
  • 6,347
  • 2
  • 22
  • 67
  • IIRC, `std::bind` already has some support for ignoring additional arguments: http://coliru.stacked-crooked.com/a/ab538d4302311c64 – dyp Sep 15 '16 at 14:49
  • @dyp Thank. It is so close, but I don't know how to adopt it to this case (template). Moreover, doesn't it require modification when calling the class (Thus, so many users of this class have to be modified.)? I would like to hear. :) – javaLover Sep 16 '16 at 06:58

1 Answers1

1

Variadic templates, partial specialization and SFINAE can help you.

If you accept to duplicate the test() method, you can do something like

#include <iostream>

using HashStruct = std::size_t;

template<typename ... AA>
using HashFunction = HashStruct & (*)(AA ... );

HashStruct &  hf1 (std::size_t s)
 { static HashStruct val {0U}; return val = s; }

HashStruct &  hf2 (std::size_t s, int i)
 { static HashStruct val {0U}; return val = s + std::size_t(i); }

template <typename Tf, Tf F>
class Collection;

template <typename K, typename ... I, HashFunction<K, I...> F>
class Collection<HashFunction<K, I...>, F>
 {
   public: 

      template <std::size_t N = sizeof...(I)>
      typename std::enable_if<N == 0U, void>::type test ()
       {
         K k=K();

         HashStruct & hh = F(k);

         std::cout << "case 0 (" << hh << ")" << std::endl;
       }

      template <std::size_t N = sizeof...(I)>
      typename std::enable_if<N == 1U, void>::type test ()
       {
         K k=K();

         HashStruct & hh = F(k, 100);

         std::cout << "case 1 (" << hh << ")" << std::endl;
       }
 };

int main ()
 {
   Collection<HashFunction<std::size_t>, hf1>       c1;
   Collection<HashFunction<std::size_t, int>, hf2>  c2;

   c1.test(); // print "case 0 (0)"
   c2.test(); // print "case 1 (100)"
 }

But, if you can pass the extra argument to test(), you don't need SFINAE, you can create a single test() method and all is simpler

#include <iostream>

using HashStruct = std::size_t;

template<typename ... AA>
using HashFunction = HashStruct & (*)(AA ... );

HashStruct &  hf1 (std::size_t s)
 { static HashStruct val {0U}; return val = s; }

HashStruct &  hf2 (std::size_t s, int i)
 { static HashStruct val {0U}; return val = s + std::size_t(i); }

template <typename Tf, Tf F>
class Collection;

template <typename K, typename ... I, HashFunction<K, I...> F>
class Collection<HashFunction<K, I...>, F>
 {
   public: 
      void test (I ... i)
       {
         K k=K();

         HashStruct & hh = F(k, i...);

         std::cout << hh << std::endl;
       }
 };

int main ()
 {
   Collection<HashFunction<std::size_t>, hf1>       c1;
   Collection<HashFunction<std::size_t, int>, hf2>  c2;

   c1.test();    // print "0"
   c2.test(100); // print "100"
 }
max66
  • 65,235
  • 10
  • 71
  • 111