gpt4 book ai didi

c++ - 如何专门化容器和枚举的模板

转载 作者:行者123 更新时间:2023-12-01 14:44:07 25 4
gpt4 key购买 nike

我试图专门针对枚举类型和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) Containerstd::vector<int>
2) Container::value_typeint
因此,该特化变为:
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 VERSION IS CALLED.

WRAPPER CONTAINER VERSION IS CALLED.

关于c++ - 如何专门化容器和枚举的模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58944807/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com