如何制作至少适用于的功能模板
枚举std::vector<T>
的任何类型,枚举,std::vector<E>
,E
?
我尝试使用重载解析和enable_if
进行了以下操作,但是虽然它适用于int
和vector<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>
有一个特殊的重载,为什么它不起作用?
答案 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));
}
此处T
为std::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>(...)
。这意味着,在尝试解决此重载时,T
为std::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
参数中推导E
为tag
,就像您原来想要的那样,而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