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