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.
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"
}
来源:https://stackoverflow.com/questions/39507686/function-as-template-parameter-ift-receive-2-paramta-b-else-ta