【发布时间】:2019-11-20 00:18:07
【问题描述】:
我正在尝试为枚举类型和 stl 容器类型专门提供一个简单的功能。 SFINAE 的想法适用于使用 enable_if 的枚举,但是类似的 stl 容器技术不起作用(我知道依赖 value_type 的存在并假设它是容器不是一个好主意,但这不是重点)。
template <typename T, typename = void>
struct wrapper {
static T getValue()
{
std::cout<<"\n WRAPPER DEFAULT VERSION IS CALLED.\n";
return T();
}
};
template<typename T>
struct wrapper<T,typename std::enable_if<std::is_enum<T>::value>::type>{
static T getValue()
{
std::cout<<"\n WRAPPER ENUM VERSION IS CALLED.\n";
return T();
}
};
template<typename Container>
struct wrapper<Container, typename Container::value_type> {
static Container getValue()
{
std::cout<<"\n WRAPPER CONTAINER VERSION IS CALLED.\n";
return Container();
}
};
int main()
{
//En is an enum type
En en = (En) wrapper<En>::getValue(); //Prints ENUM VERSION
std::vector<int> vec;
vec = wrapper<std::vector<int>>::getValue(); //Prints DEFAULT VERSION
}
请告诉我为什么第二次调用会转到默认实现?
解决方案:
感谢 Sam Varshavchik,我发现我错过了第二个参数应该解析为 void 的点(就像在 enable_if::type 的情况下一样),否则我必须显式传递第二个参数才能进行调用解析为容器版本:
wrapper<std::vector<int>, int>::getValue();
为了使原始版本能够正常工作(在 C++ 17 之前 void_t 不可用),我正在创建自己的类型特征,这依赖于容器具有为其定义的迭代器类型这一事实:
template <typename T1, typename T2 = void>
struct container_trait
{};
template <typename T1>
struct container_trait<T1, typename T1::iterator> {
typedef void type;
};
现在我的容器版本的包装器变成了:
template<typename Container>
struct wrapper<Container, typename container_trait<Container, typename Container::iterator>::type> {
static Container getValue(const rapidjson::Value& rjv)
{
std::cout<<"\n WRAPPER CONTAINER VERSION IS CALLED.\n";
return Container();
}
};
现在同样的调用工作得很好:
vec = wrapper<std::vector<int>>::getValue(); //Prints CONTAINER VERSION
【问题讨论】:
-
您的容器专业化需要两个模板参数(第二个不是 void)。因此,在您的示例中永远不会调用它。您可能需要编写类似于
is_enum的类型特征,但对于包含value_type的标准容器(根据您的要求),然后以相同的方式使用它。查看std::void_t以及它是如何使用的。 -
感谢@DeiDei,我最终为容器编写了一个类型特征,它依赖于 value_type 的存在(尽管这种对 value_type 的依赖听起来对我来说不是很有说服力)。但目前想不出更好的方法。
-
也许最好检查
const_iterator,因为它与容器更相关。还要检查stackoverflow.com/questions/12042824/…