1

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

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

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

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

1 回答 1

1

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

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

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

  3. 升压。任何。这将两种解决方案概括为将任意数量的不相关类型包装在持有者对象中。主要优点是您具有值语义,并且没有手动内存管理(尽管这是在幕后完成的)。唯一实际的缺点是它需要 Boost,这在一些限制性的公司环境中是不可能的。

于 2013-05-02T20:27:54.830 回答