gpt4 book ai didi

c++ - std::enable_if 在模板参数上确定 STL 容器

转载 作者:行者123 更新时间:2023-11-28 05:45:55 25 4
gpt4 key购买 nike

基于 an answer from Nawaz我想使用 enable_if 来确定模板参数是否是容器,如果是,我想显示类型名称的自定义消息,而不是 typeid 中的名称。我以两种方式实现了模板特化。代码编译并运行,但在这两种情况下都不会调用专门的方法。我假设我错误地使用了 enable_if,这里正确的应用是什么?

我在代码序列下面放了一个独立的小控制台应用程序是:(a) 所需的包含文件 (b) 预备模板代码(使用 SFINAE) (c) 应该执行任务的结构的两个实现 (d) 一些客户端代码

#include <typeinfo>
#include <string>
#include <list>
#include <vector>
#include <iostream>
using namespace std;

template<typename T>
struct has_const_iterator
{
private:
typedef char yes;
typedef struct { char array[2]; } no;

template<typename C> static yes test(typename C::const_iterator*);
template<typename C> static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
typedef T type;
};

template <typename T>
struct has_begin_end
{
template<typename C> static char(&f(typename std::enable_if<
std::is_same<static_cast<typename C::const_iterator(C::*)() const>(&C::begin),
typename C::const_iterator(C::*)() const>::value, void>::type*))[1];

template<typename C> static char(&f(...))[2];

template<typename C> static char(&g(typename std::enable_if<
std::is_same<static_cast<typename C::const_iterator(C::*)() const>(&C::end),
typename C::const_iterator(C::*)() const>::value, void>::type*))[1];

template<typename C> static char(&g(...))[2];

static bool const beg_value = sizeof(f<T>(0)) == 1;
static bool const end_value = sizeof(g<T>(0)) == 1;
};
template<typename T>
struct is_container : std::integral_constant<bool,
has_const_iterator<T>::value &&
has_begin_end<T>::beg_value &&
has_begin_end<T>::end_value>
{ };

struct TypeName {
template <typename T>
static const char* get() {
return typeid(T).name();
}

template <typename T, typename std::enable_if<is_container<T>::value>::type >
static const char* get()
{
typedef typename T::value_type ElementType;
std:string containerType = "";
if (std::is_same<decltype(std::vector<ElementType>), T>::value) {
containerType = "(Vector) ";
}
if (std::is_same<decltype(std::list<ElementType>), T>::value) {
containerType = "(List) ";
}
std::string returnString = "Container " + containerType;
returnString += " of ";
returnString += get<ElementType>();
return returnString.c_str();
}
};

template <typename T> struct GypeName {

static const char* get() {
return typeid(T).name();
}

template <class = typename std::enable_if<is_container<T>::value>::type >
static const char* get()
{
typedef typename T::value_type ElementType;
std:string containerType = "";
if (std::is_same<decltype(std::vector<ElementType>), T>::value) {
containerType = "(Vector) ";
}
if (std::is_same<decltype(std::list<ElementType>), T>::value) {
containerType = "(List) ";
}
std::string returnString = "Container " + containerType;
returnString += " of ";
returnString += GypeName<ElementType>::get();
return returnString.c_str();
}
};



int main(int argc, char** argv) {
cout << is_container<int>::value << endl;
cout << is_container<std::vector<int>>::value << endl;
cout << TypeName::get<int>() << endl;
cout << TypeName::get<std::string>() << endl;
cout << TypeName::get<std::vector<int>>() << endl;
cout << TypeName::get<std::vector<std::vector<int>>>() << endl;
cout << GypeName<int>::get() << endl;
cout << GypeName<std::string>::get() << endl;
cout << GypeName<std::vector<int>>::get() << endl;
cout << GypeName<std::vector<std::vector<int>>>::get() << endl;
return 0;
}

这一切的输出是

0
1
int
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
class std::vector<int,class std::allocator<int> >
class std::vector<class std::vector<int,class std::allocator<int> >,class std::allocator<class std::vector<int,class std::allocator<int> > > >
int
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
class std::vector<int,class std::allocator<int> >
class std::vector<class std::vector<int,class std::allocator<int> >,class std::allocator<class std::vector<int,class std::allocator<int> > > >

在任何一种情况下都不调用专门的函数。

最佳答案

您可以使用以下内容:

struct TypeName {
template <typename T>
static
std::enable_if_t<!is_container<T>::value, const char*>
get() {
return typeid(T).name();
}

template <typename T>
static
std::enable_if_t<is_container<T>::value, std::string>
get()
{
typedef typename T::value_type ElementType;
std::string containerType = "";
if (std::is_same<std::vector<ElementType>, T>::value) {
containerType = "(Vector) ";
}
if (std::is_same<std::list<ElementType>, T>::value) {
containerType = "(List) ";
}
return (boost::format("Container %s of %s")
% containerType
% TypeName::get<ElementType>()).str();
}
};

Demo

请注意,std::string 被视为char 的容器。
由于您对 vector/列表有特定的(运行时 :( ) 情况,您可以只对这两个使用专门化:

namespace detail
{
template <typename T> struct TypeName
{
auto operator ()() const { return typeid(T).name(); }
};

template <template <typename...>class C, typename T, typename...Ts>
struct TypeName<C<T, Ts...>>
{
auto operator()() const {
return (boost::format("container of %s") % TypeName<T>{}()).str();
}
};

template <typename T, typename A>
struct TypeName<std::vector<T, A>>
{
auto operator()() const {
return (boost::format("Vector of %s") % TypeName<T>{}()).str();
}
};

template <typename T, typename A>
struct TypeName<std::list<T, A>>
{
auto operator()() const {
return (boost::format("List of %s") % TypeName<T>{}()).str();
}
};

}

struct TypeName {
template <typename T>
static auto get() {
return detail::template TypeName<T>{}();
}
};

Demo

关于c++ - std::enable_if 在模板参数上确定 STL 容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36225586/

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