用于引用类本身的模板,而不是使用模板的类
Template for referencing classes themselves rather than a class that uses templates
所以我有一个不寻常的情况,我的模板和教程经验似乎没有涵盖。
我正在编写一个程序,该程序可以自动为另一个程序签署消息,该程序无法执行,但API有限。有一个配置文件,其中包含一个字符串,告诉我的程序使用哪个哈希来签名消息。该字符串存储在signatureAlgorithm对象中,该对象存储摘要、摘要的大小,并为摘要的编码提供了一些选项。我正在使用Crypto++库进行哈希函数。现在,我有一大组if/else-if语句,每个语句中有三个命令,这取决于字符串所说的算法应该是什么,如下所示:
void signatureAlgorithm::createDigest(string input)
{
bool digestFail = false;
if (_algorithm == "md5")
{
//byte digest[ CryptoPP::MD5::DIGESTSIZE ];
_digestSize = (CryptoPP::MD5::DIGESTSIZE);
_digest = new byte[ _digestSize ];
CryptoPP::MD5().CalculateDigest( _digest, (byte*) input.c_str(), input.length() );
}
.....
else if (_algorithm == "sha256")
{
_digestSize = (CryptoPP::SHA256::DIGESTSIZE);
_digest = new byte[ _digestSize ];
CryptoPP::SHA256().CalculateDigest( _digest, (byte*) input.c_str(), input.length() );
}
else if (_algorithm == "sha512")
{
_digestSize = (CryptoPP::SHA512::DIGESTSIZE);
_digest = new byte[ _digestSize ];
CryptoPP::SHA512().CalculateDigest( _digest, (byte*) input.c_str(), input.length() );
}
else
digestFail = true;
if (!digestFail)
_ready = true;
else
_ready = false;
}
_digestSize将摘要大小存储在对象中,就像_digest对摘要的字节所做的那样(字节是typedef const unsigned char*),在其他函数中使用_ready来确定在将值提供给调用程序之前是否已对其进行了消化,或者改为向程序返回错误。
我最终计划切换到映射以使事情更高效、更整洁,但在此之前,我必须找到一种方法,使_distSize的设置和CreateDigest()的调用更通用。我试图避免修改库,因为我想在最终版本中以编译的形式保持Crypto++的FIPS状态,但目前我只是使用源代码进行测试,如果这有什么不同的话。
我考虑过模板,每个if语句的内部部分只是设置值,但我找不到以这种方式使用模板的例子。我发现它们用于在有其他函数的地方创建类,但在这种情况下,如果我在这里思考,我只需要能够创建一个简单地指向另一个类的泛型类。
我尝试做的伪代码:
class tempClass {};
if (_algorithm == "md5")
{
tempClass = CryptoPP::MD5
}
......
else
digestFail = true;
_digestSize = (tempClass::DIGESTSIZE);
_digest = new byte[_digestSize];
tempClass().CalculateDigest( _digest, (byte*) input.c_str(), input.length() );
-Jimmy
编辑:虽然我在评论中说,由于类树中的分叉,继承不起作用,但事实证明,我一直在使用的文档是最新版本的。我用于测试的版本和FIPS版本更旧,以前像MD5等函数被拆分成一个单独的"弱"结构。
第2版:然而,我仍然很好奇,即使这些类是分叉的,并且不是从同一个地方继承CalculateDigest,是否有办法做到这一点。
编辑3:约翰·班德拉回答了这个问题,但我只需要稍微改变一下他给我的。答案的注释中有更改。谢谢大家!
将代码分解为类似的模板函数
//假设_digest和_digest size是类成员;
template<class Digest>
byte* doDigest(string input, int& digestSize){
int digestSize = (Digest::DIGESTSIZE);
byte* digest = new byte[ digestSize ];
Digest().CalculateDigest( digest, (byte*) input.c_str(), input.length() );
return digest;
}
然后在您的createDigest函数中执行此
if (_algorithm == "md5")
{
_digest = doDigest<CryptoPP::MD5>(input,_digestSize);
}
else if (_algorithm == "sha256")
{
_digest = doDigest<CryptoPP::SHA256>(input,_digestSize);
}
...
偏离主题,但您可能需要考虑使用矢量而不是字节*
另一种方法,但使用更多的模板元编程
有关完整的可运行示例,请参阅
https://gist.github.com/4164700
template<class Digest, class... T>
struct DigestMatcher{
template<class U, class ... V>
static byte* doDigest(std::string input, int& digestSize,std::string algorithm,U firstalgorithm, U nextalgorithm, V... algorithms){
if(algorithm==firstalgorithm){
return doDigest(input,digestSize);
}
else{
return DigestMatcher<T...>::doDigest(input,digestSize,algorithm,nextalgorithm,algorithms...);
}
}
template<class U>
static byte* doDigest(std::string input, int& digestSize,std::string algorithm, U firstalgorithm){
if(algorithm==firstalgorithm){
return doDigest(input,digestSize);
}
else{
std::cout << algorithm << " invalid" << std::endl;
return 0;
}
}
static byte* doDigest(std::string input, int& digestSize){
// Cout for debug purposes
std::cout << "using " << typeid(Digest).name() << std::endl;
digestSize = Digest::DIGESTSIZE;
byte* digest = new byte[ digestSize ];
Digest().CalculateDigest( digest, (byte*) input.c_str(), input.length() );
return digest;
}
};
然后是您的呼叫代码
void signatureAlgorithm::createDigest(std::string input)
{
_digest = DigestMatcher<MD5,SHA256,SHA512>::doDigest(input,_digestSize,_algorithm,"md5","sha256","sha512");
if(_digest)
_ready = true;
else
_ready = false;
}
- std::vector 是否有用于引用的复制构造函数?
- C++模板,用于通过常量引用和原始指针传递向量
- 具有字符串文本构造函数的类不适用于 const 引用初始化
- std::bind 不适用于引用?
- 对于实际指针类型,用于检测类似指针(可取消引用)类型的模板函数失败
- 为什么常量双 &&&不适用于左值引用?
- 引用在用于创建对象时更改值
- Unity3D 导入 C++ DLL 用于按引用方法传递
- QT用于Android-对AnativeWindow_FromSurface的未定义引用
- 如何在 C++14 中编写用于调用 Fortran 函数的通用包装器(按引用调用 --按值调用>)
- 用户定义的转换运算符不适用于引用
- 取消引用适用于 ptr->运算符*(),但不适用于 *ptr
- 用于引用类本身的模板,而不是使用模板的类
- 没有用于引用映射的可行重载运算符
- 为什么数字10用于引用整数类型0
- 用于在C++中返回引用的语法-与号
- 声明引用适用于类,但不适用于主函数
- 使用指针或不将其用于类引用。有什么区别?
- 通过添加一些特殊字符,使 /* 的含义用于取消引用和划分不用于注释
- C++ "<<"运算符错误(用于引用向量的内容)