返回具有模板功能的通用类型

returning a generic type with template functions

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

我是使用模板的新手,我想制作一个返回通用类型的函数。我制作了一个非常简单的模板

enum tag { SHORT, INT, FLOAT, DOUBLE };
template <typename T>
T get_val(tag t){
    switch (t) {
    case SHORT: return .. //returns a short;
    case INT: return .. //returns a int;
    case FLOAT: return .. //returns a float;
    case DOUBLE: return .. //returns a double;
    }
}

问题在于,浮子和双打作为整数编号返回。所以我想知道为什么会发生这种情况,如果有一种方法可以正确使用。

您不得使用类似的 switch语句使用其他返回类型。

但是,如果在编译时已知get_val的输入,则可以使用模板元编程技术来获取所需的东西。

enum tag { SHORT, INT, FLOAT, DOUBLE };
template <tag t> struct return_type_chooser;
template <> struct return_type_chooser<SHORT>
{
   using type = short;
};
template <> struct return_type_chooser<INT>
{
   using type = int;
};
template <> struct return_type_chooser<FLOAT>
{
   using type = float;
};
template <> struct return_type_chooser<DOUBLE>
{
   using type = double;
};
template <tag t>
typename return_type_chooser<T>::type get_val()
{
   ...
}

您可以使用:

get_val<SHORT>()

但不是

get_val(SHORT)

更新,响应OP的评论

如果仅在运行时知道get_val的输入,则std::any(C 17)或boost::any应作为返回类型工作。

我建议使用有限类型的有限子集中的类型进行变体和运行时检查:

使用一个公共接口进行正确类型的枚举的变体(这是一个天真的版本,您应该真正使用std::variantget_if):

enum variant_type
{
    variant_null,
    variant_int,
    variant_float,
    variant_double,
}

class variant
{
public:
    // Add constructors with the correct type for the
    // underlying storage
    variant() = default;
    variant(int x);
    variant(float x);
    variant(double x);
    // ensure you can check for empty variants and check the type
    explicit operator int() const;
    explicit operator float() const;
    explicit operator double() const;
    explicit operator bool() const;
    variant_type type() const;
private:
    variant_type type_ = variant_null;
    void* data_ = nullptr;
};

然后,添加许多自定义功能或方法过载,使您可以在运行时选择正确的方法:

class my_handler
{
public:
    my_handler(const variant& v)
    {
        switch (v.type()) {
            case variant_null;
                open(nullptr);      break;
            case variant_int;
                open(int(v));       break;
            case variant_float;
                open(float(v));     break;
            case variant_double;
                open(double(v));    break;
        }
    }
private:
    void open(std::nullptr_t nullp);
    void open(int x);
    void open(float x);
    void open(double x);
};

这使您可以拥有一个对有限类型子集的通用的公共接口,但是您可以避免在编译时知道正确的类型。

可以使用std::variantget_if更惯用地完成这一切,而不是编写自己的自定义变体类。我只是作为一个(例如Windows API和QT)实现了多少库(例如Windows API和QT)的(效率低下的)示例。