模板函数返回不同的类型

Template function to return different types

本文关键字:类型 返回 函数      更新时间:2023-10-16

是否有可能在运行时确定不同类型的方法返回值?

我正在写一些东西,将编码和解码使用不同的密码。每个密码都有一个不同类型的密钥,在某些阶段,我需要允许密码获取这个密钥。

为了避免编写三个(目前有三个密码)单独的方法来返回不同类型的密钥,并且一次只使用一个密码,我试图做以下操作:

in parser.h:

    template <typename T>
    T get_key(void) const;

in 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;
  ^

您可以使用3种方法,所有这些方法都在评论中提到过。以下是在它们之间进行选择的更多细节和权衡:

  1. 工厂方法。正如@KerrekSB在评论中提到的,您必须定义每个键类型的抽象基类和子类。工厂函数的返回类型是指向AbstractKey的指针(最好是处理资源管理的智能指针)。然而,工厂的实现是基于您正在解析的运行时值的if-else阶梯、switch语句或花哨的表查找。这是因为协变返回类型。有关工作示例,请参见本网站的设计模式。主要的缺点是你必须编写大量的样板(例如,向工厂注册新类型等),内置类型被排除在外,并且你返回的对象没有值语义。

  2. Boost.Variant 。@AnatolyS在评论中提到了这一点。这种方法将有限数量的不相关类型包装在联合中,并允许您一次只使用其中一种类型,而不会产生动态分配开销。有关如何使用它,请参阅Boost文档。它的主要缺点是它的可扩展性不强,而且要动态选择您想要的键类型需要相当多的技巧。

  3. Boost.Any 。这将两种解决方案一般化,将任意数量的不相关类型包装在一个holder对象中。其主要优点是具有值语义,而无需手动内存管理(尽管这是在后台完成的)。唯一实际的缺点是它需要Boost,这在一些限制性的公司设置中是不可能的。