C++的 value_type 可以从 iterator_traits 扩展到所有类型吗?

发布于 2024-08-22 11:11:35 字数 815 浏览 13 评论 0原文

我想创建一个类似于 std::iterator_traits::value_type 的构造,它可以使用相同的语法无缝地用于所有类型。假设我们有以下内容:

template <typename T>
struct value_type {
  typedef T type;
};

#define VALUE_TYPE(T) typename value_type<T >::type

这适用于 POD 类型。我可以将它专门用于我自己的类:

struct MyClass {
  typedef float value_type;
};

template <>
struct value_type<MyClass> {
  typedef MyClass::value_type type;
};

尽管我更愿意在理想的世界中避免额外的 value_type 实例化。

问题出在 STL 迭代器上。我需要一种专业化来帮助我了解迭代器层次结构。这会失败,因为编译器选择基本情况:

template <>
struct value_type<std::_Iterator_base_aux> {  // MSVC implementation
  typedef value_type type;
};

选择层次结构较高的类(_Iterator_with_base 是最自然的,因为那是定义 value_type 的地方)失败,因为它需要将所有迭代器特征指定为模板参数。

我想要做的事情在 C++ 中是否可行?

I would like to create a construct similar to std::iterator_traits::value_type that can work seamlessly for all types using the same syntax. Imagine we have the following:

template <typename T>
struct value_type {
  typedef T type;
};

#define VALUE_TYPE(T) typename value_type<T >::type

This will work for POD types. I can specialize it for my own class:

struct MyClass {
  typedef float value_type;
};

template <>
struct value_type<MyClass> {
  typedef MyClass::value_type type;
};

though I would prefer to avoid extra value_type instantiations in an ideal world.

The problem is with STL iterators. I need a specialization that gets me to the iterator hierarchy. This fails because the compiler chooses the base case:

template <>
struct value_type<std::_Iterator_base_aux> {  // MSVC implementation
  typedef value_type type;
};

Choosing a class higher up the hierarchy (_Iterator_with_base would be most natural because that is where value_type is defined) fails because it requires specifying all the iterator traits as template arguments.

Is what I'm trying to do even possible in C++?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

铁憨憨 2024-08-29 11:11:35

您可以使用 SFINAE 来检测 value_type typedef 是否存在。无需专门针对单个类型(这可能是不可能的,因为您完全依赖于内部实现细节)。

#include <vector>

template <class T>
struct has_value_type
{
    typedef char true_type;
    typedef char false_type[2];

    //template not available if there's no nested value_type in U's scope
    template <class U>
    static true_type test(typename U::value_type* ); 

    //fallback
    template <class U>
    static false_type& test(...);

    //tests which overload of test is chosen for T
    static const bool value = sizeof(test<T>(0)) == sizeof(true_type);
};

template <class T, bool b>
struct value_type_impl;

template <class T>
struct value_type_impl<T, false> //if T doesn't define value_type
{
    typedef T type;
};

template <class T>
struct value_type_impl<T, true> //if T defines value_type
{
    typedef typename T::value_type type;
};

template <class T>
struct value_type: value_type_impl<T, has_value_type<T>::value>
{
};

struct MyClass {
  typedef float value_type;
};

template <class T>
int foo(T )
{
    return typename value_type<T>::type();
}

int main()
{
    foo(MyClass());
    std::vector<int> vec;
    foo(vec.begin());
    foo(10);
}

You can use SFINAE to detect the presence of the value_type typedef. No need to specialize for individual types (which might not be possible, since you'd be relying entirely on internal implementation details).

#include <vector>

template <class T>
struct has_value_type
{
    typedef char true_type;
    typedef char false_type[2];

    //template not available if there's no nested value_type in U's scope
    template <class U>
    static true_type test(typename U::value_type* ); 

    //fallback
    template <class U>
    static false_type& test(...);

    //tests which overload of test is chosen for T
    static const bool value = sizeof(test<T>(0)) == sizeof(true_type);
};

template <class T, bool b>
struct value_type_impl;

template <class T>
struct value_type_impl<T, false> //if T doesn't define value_type
{
    typedef T type;
};

template <class T>
struct value_type_impl<T, true> //if T defines value_type
{
    typedef typename T::value_type type;
};

template <class T>
struct value_type: value_type_impl<T, has_value_type<T>::value>
{
};

struct MyClass {
  typedef float value_type;
};

template <class T>
int foo(T )
{
    return typename value_type<T>::type();
}

int main()
{
    foo(MyClass());
    std::vector<int> vec;
    foo(vec.begin());
    foo(10);
}
轻拂→两袖风尘 2024-08-29 11:11:35

UncleBens已经使用了SFINAE,但实际上还有更简单的:

template <class T>
struct value_type
{
  typedef typename T::value_type type;
};

现在,如果你想将它与你控制的类一起使用,最简单的方法是:

struct MyClass { typedef float value_type; };

BOOST_MPL_ASSERT((boost::is_same< MyClass::value_type,
                                  typename value_type<MyClass>::type >));

如果你想将它用于你不控制的类,您仍然有专门化:

struct ThirdPartyClass {};

template <>
struct value_type<ThirdPartyClass> { typedef int type; }

如果您尝试对没有内部 typedef 且没有可用专门化的类使用 value_type ,则会出现编译错误(并且乍一看你不太可能理解的消息......)

UncleBens has used SFINAE, but there is actually simpler:

template <class T>
struct value_type
{
  typedef typename T::value_type type;
};

Now, if you want to use it with a class you control, the easiest way is:

struct MyClass { typedef float value_type; };

BOOST_MPL_ASSERT((boost::is_same< MyClass::value_type,
                                  typename value_type<MyClass>::type >));

And if you want to use for a class you do not control, you still have specialization:

struct ThirdPartyClass {};

template <>
struct value_type<ThirdPartyClass> { typedef int type; }

If you try to use value_type for a class that does not have an inner typedef and for which no specialization is available, it's a compilation error (and a message you are not likely to understand at first glance...)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文