不同类型的模板功能

时间:2018-04-29 16:14:32

标签: c++ templates overloading

如何制作至少适用于的功能模板 枚举std::vector<T>的任何类型,枚举,std::vector<E>E

我尝试使用重载解析和enable_if进行了以下操作,但是虽然它适用于intvector<int>,但它失败并且vector<E>说它无法找到要调用的函数:

struct Details
{
    template<typename T>
    typename std::enable_if<std::is_enum<T>::value, T>::type
        get_impl(const std::string& key, T*) const
    {
        return static_cast<T>(get_impl<int>(key, static_cast<int*>(0)));
    }

    template<typename T>
    int get_impl(const std::string& key, int*) const
    {
        return int();
    }

    template<typename T>
    typename std::enable_if<std::is_enum<T>::value, std::vector<T>>::type
        get_impl(const std::string& key, std::vector<T>*) const
    {
        return std::vector<T>();
    }


    template<typename T>
    std::vector<int> get_impl(const std::string& key, std::vector<int>*) const
    {
        return T();
    }

    template<typename T>
    T getValue(const std::string& key)
    {
        return get_impl<T>(key, static_cast<T*>(0));
    }
};

int main()
{
    enum E {A, B};
    Details details;
    details.getValue<int>(""); // ok
    details.getValue<std::vector<int>>(""); // ok
    details.getValue<std::vector<E>>(""); // error: no matching function
}

我对vector<enum>有一个特殊的重载,为什么它不起作用?

1 个答案:

答案 0 :(得分:3)

你的问题是你没有保持你的类型,你正在混合和匹配提供明确的类型和模板扣除。如果你仔细看看你得到的错误信息,你会看到发生了什么。

在enum的情况下,你正在打电话:

details.getValue<std::vector<E>>("");

哪个电话:

template<typename T>
T getValue(const std::string& key)
{
    return get_impl<T>(key, static_cast<T*>(0));
}

此处Tstd::vector<E>。到现在为止还挺好。现在,您要调用的重载是:

template<typename T>
typename std::enable_if<std::is_enum<T>::value, std::vector<T>>::type
    get_impl(const std::string& key, std::vector<T>*) const

但你称之为get_impl<T>(...)。这意味着,在尝试解决此重载时,Tstd::vector<E>,最后一个参数为std::vector<std::vector<E>>*。所以这个函数模板根本就不是候选者 - 最后一个参数不匹配,即使它确实如此,std::vector<E>也不是枚举,所以enable_if会排除它。

解决问题的方法是将所有内容保留在演绎世界中。当我们在那里时,避免使用空指针来执行标记调度。这很令人困惑 - 因为现在代码的某些部分使用指针作为指针,而有些部分只是将它们用作类型。我们可以只使用一种特殊类型作为类型:

template <typename T> struct tag { };

并将其传递给:

template <typename T>
T getValue(std::string const& key ) {
    return get_impl(key, tag<T>{});
}

请注意,我不再指定get_impl的类型,它将被推断出来。现在,您的枚举案例是:

template<typename T>
typename std::enable_if<std::is_enum<T>::value, std::vector<T>>::type
get_impl(const std::string& key, tag<std::vector<T>>) const

这将有效。我们会从T参数中推导Etag,就像您原来想要的那样,而E是枚举,所以这是有效的。

请注意,即使您使用的是C ++ 11,也可以使用别名模板。因此,虽然您无权访问std::enable_if_t,但您仍然可以写:

namespace xstd {
    template <bool B, typename T>
    using enable_if_t = typename std::enable_if<B, T>::type;
}

这使得所有这些内容更容易阅读:

template<typename T>
xstd::enable_if_t<std::is_enum<T>::value, std::vector<T>>
get_impl(const std::string& key, tag<std::vector<T>>) const
相关问题