我试图专门针对枚举类型和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
第二次调用默认实现的原因非常简单。
只需手动计算出如何为容器版本模板的参数推导参数:
template<typename Container>
struct wrapper<Container, typename Container::value_type>
您正在实例化以下模板:
wrapper<std::vector<int>>
所以:
1)Container
是std::vector<int>
2)Container::value_type
是int
因此,该专业化变为:
struct wrapper<std::vector<int>, int>
但是,您仅在调用:
wrapper<std::vector<int>, void>
因为它void
是第二个模板参数的默认值,所以它与错误的专业化匹配。
解决方案非常简单,容器专门化应该是:
#include <type_traits>
template<typename Container>
struct wrapper<Container, std::void_t<typename Container::value_type>> {
std::void_t
是C ++ 17,stackoverflow.com上还有其他问题,说明了如何针对较早的C ++标准实现它。完整的例子:
#include <vector>
#include <iostream>
#include <type_traits>
enum En {};
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, std::void_t<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
}
结果:
WRAPPER ENUM版本已调用。
包装容器版本已调用。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句