C++ 用于引用类本身而不是使用模板的类的模板
所以我有一个不寻常的情况,我在模板和教程方面的经验似乎没有涵盖 我正在编写一个程序,自动为另一个程序的消息签名,该程序无法执行,但API有限。有一个配置文件,其中包含一个字符串,告诉我的程序使用哪个散列对消息进行签名。 此字符串存储在signatureAlgorithm对象中,该对象存储摘要、摘要应为的大小,并提供了一些用于摘要编码的选项。 我正在使用Crypto++库来实现散列函数。 现在,我有一大组if/else if语句,每个语句中有三个命令,具体取决于字符串表示的算法应该是什么,如下所示:C++ 用于引用类本身而不是使用模板的类的模板,c++,C++,所以我有一个不寻常的情况,我在模板和教程方面的经验似乎没有涵盖 我正在编写一个程序,自动为另一个程序的消息签名,该程序无法执行,但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在其他函数中用于确定在将值传递给调用程序之前已对其进行了摘要,或者将错误返回给程序
我最终计划切换到map,以使事情更高效、更整洁,但在此之前,我必须找到一种方法,使_digestSize的设置和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() );
-吉米
编辑:虽然我在评论中说继承因为类树中的分叉而不起作用,但事实证明我使用的文档是最新版本的。我用于测试的版本和FIPS版本都比MD5等功能分解为单独的“弱”结构之前更旧
编辑2:然而,我仍然很好奇,即使这些类是分叉的,并且没有从同一个地方继承CalculateDigest,是否有办法做到这一点
编辑3:约翰·班德拉回答了这个问题,但我不得不稍微改变一下他给我的东西。答案的注释中有更改。谢谢大家 将代码分解成如下模板函数 //假设_digest和_digestsize是类成员
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;
}
模板
字节*doDigest(字符串输入、int和digestSize){
int digestSize=(Digest::digestSize);
字节*摘要=新字节[摘要大小];
Digest().CalculateDigest(Digest,(byte*)input.c_str(),input.length());
返回摘要;
}
然后在createDigest函数中执行以下操作
if (_algorithm == "md5")
{
_digest = doDigest<CryptoPP::MD5>(input,_digestSize);
}
else if (_algorithm == "sha256")
{
_digest = doDigest<CryptoPP::SHA256>(input,_digestSize);
}
...
if(_算法==“md5”)
{
_digest=doDigest(输入,_digestSize);
}
else if(_算法==“sha256”)
{
_digest=doDigest(输入,_digestSize);
}
...
话题,但你可能想考虑使用矢量代替字节**/p>
另一种方式,但是更多的模板元编程
有关完整的可运行示例,请参阅模板
结构消化匹配器{
模板
静态字节*doDigest(std::string输入、int和digestSize、std::string算法、U firstalgorithm、U nextalgorithm、V…算法){
if(算法==firstalgorithm){
返回doDigest(输入,摘要大小);
}
否则{
返回DigestMatcher::doDigest(输入、digestSize、算法、nextalgorithm、算法…);
}
}
模板
静态字节*doDigest(std::string输入、int&digestSize、std::string算法、U算法){
if(算法==firstalgorithm){
返回doDigest(输入,摘要大小);
}
否则{
std::我不太确定crpyto++库,但由于不同的crpyto类实现相同的CalculatedGewst
。它们是否有可能继承自一个公共父类和CalculatedGewst
是一个虚拟函数?如果是这样,您只需获得一个指向父类的指针并执行此任务。您正在寻找继承、虚拟函数和(可选)类工厂。其中一些类从更高的类继承虚拟函数,但一些类似MD2的类处于更高的分叉级别。顶层似乎没有CalculateDigest,但就在下面是MD2和类似的类,然后其他类(如MD5和SHA)在更下面继承的子类中。我考虑过直接继承,但从它们位于多个分支上,我不想修改Crypto++我想知道是否有其他方法…似乎可以工作,但出现了问题。您有int digestSize=(CryptoPP::MD5::digestSize)
对于每个散列必须不同,并且当检查_算法时计算_digestSize。我假设我可以为DIGEST::digestSize
创建另一个模板函数。编辑:此外,字节*是Crypto++所必需的。我无法编辑库,否则它会丢失FIPS认证。考虑到我提到的调整,这是有效的。我还将doDigest设置为void,让它设置实际的私有类成员,并将其列为私有函数。为了澄清,我想我知道您对向量的建议。我不是在存储多个哈希,而是Crypto++为每个摘要使用字节数组(const unsigned char*)。之所以我可以这样设置,是因为该程序允许在更高级别上使用菊花链哈希函数,这是一些签名系统所做的。修复了它。将其替换为Digest::DIGESTSIZE。关于向量而不是字节*使用vectorbyteI,我不认为关于避免字节*的建议是正确的
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;
}