是否可以使用在运行时确定的类型返回不同类型的方法?
我正在编写将使用不同密码进行编码和解码的内容。每个密码都有一个不同类型的密钥,在某些阶段我需要允许密码获取此密钥。
为了避免编写三个(现在有三个密码)单独的方法来返回不同类型的密钥,并且一次只使用一个密码我正在尝试执行以下操作:
parser.h
中的:
template <typename T>
T get_key(void) const;
parser.cpp
中的:
/**
* The key to be used for encoding or decoding.
*
* @return The key to be used.
*/
template <typename T>
T cmdline_parser::get_key(void) const
{
if (vm.count("xor") > 0)// if xor cipher in use
return vm["xor"].as<long>();// returns a key of type long
else if (vm.count("caesar") > 0)// if caesar cipher in use
return vm["caesar"].as<int>();// returns a key of type int
else// vignere cipher in use
return vm["vignere"].as<std::string>();// returns a key of type std::string
}
我是如何尝试使用它的:
Crypt<VignereCipher, std::string, Group, Pack> c(parser.get_key());
使用clang++
进行编译得出:
main.cpp:42:61: error: no matching member function for call to 'get_key'
Crypt<VignereCipher, std::string, Group, Pack> c(parser.get_key());
~~~~~~~^~~~~~~
和
./cmdline_parser.h:40:7: note: candidate template ignored: couldn't infer template argument 'T'
T get_key(void) const;
^
答案 0 :(得分:1)
您可以使用3种方法,所有这些方法都在评论中提到。以下是更多细节和权衡,可供选择:
工厂方法。正如注释中提到的@KerrekSB,您必须定义一个抽象基类并从中定义每个键类型。工厂函数的返回类型是指向AbstractKey
的指针(最好是处理资源管理的智能指针)。然而,工厂的实现是if-else
梯形图,switch
语句或基于您正在解析的运行时值的花式表格查找。这是因为covariant return types。有关工作示例,请参阅例如关于设计模式的这个site。主要的缺点是你必须编写很多样板(例如将新类型注册到工厂等),内置类型被排除在外,并且返回的对象没有值语义。
<强> Boost.Variant 即可。 @AnatolyS在评论中提到了这一点。此方法在联合中包含有限数量的不相关类型,并允许您在没有动态分配开销的情况下仅使用其中一种类型。有关如何使用它的信息,请参阅Boost文档。主要缺点是它不是非常可扩展的,动态选择你想要的密钥类型需要bit of trickery。
<强> Boost.Any 即可。这概括了两个解决方案,以便在持有者对象内包含任意数量的不相关类型。主要的优点是你有价值语义,没有手动内存管理(虽然这是在幕后完成的)。唯一的实际缺点是它需要Boost,这在某些限制性公司环境中是不可能的。