【问题标题】:How to know whether std::iterator_traits<T>::value_type is defined [duplicate]如何知道是否定义了 std::iterator_traits<T>::value_type [重复]
【发布时间】:2012-08-14 09:34:48
【问题描述】:

可能重复:
enable_if iterator as a default template parameter?

我正在寻找在编译时了解std::iterator_traits&lt;T&gt;::value_type 是否有效且已定义的解决方案。这样做的问题是 std 库将 value_type 的声明转发到 T 中的派生类型:

typedef T::value_type value_type;

我需要在编译时知道 T::value_type 是否是有效类型以避免与 v​​alue_type 不存在相关的错误。

请考虑以下示例:

std::iterator_traits<int *>::value_type; // OK - should return that value_type exists as it's defined in specialization of std::iterator_traits

std::iterator_traits<const int *>::value_type; // OK - should return that value_type exists as it's defined in specialization of std::iterator_traits

std::iterator_traits<std::vector<int>::const_iterator> >::value_type; // OK - the value_type exists defined within std::vector<int>::const_iterator

std::iterator_traits<int>::value_type; // ERROR - the value_type is not defined within int class - this is what I'm trying to avoid to resolve the value_type of.

我需要该解决方案完全符合 C++ 标准和标准库标准并且独立于编译器。

【问题讨论】:

  • 我最近回答的这个问题可能会有所帮助:stackoverflow.com/questions/11898657/…
  • @R.MartinhoFernandes:事实上,这看起来像是复制品。
  • 我认为整个问题在于它返回 iterator_category 存在: typedef typename _Iter::iterator_category iterator_category;在 std::iterator_traits 默认定义。您的 sfinae 将返回它存在,即问题。
  • @PavelCelba 你试过了吗?除非_Iter::iterator_category 存在,否则std::iterator_traits&lt;T&gt;::iterator_category 会导致替换失败(value_type 也是如此)。
  • 是的,它不会导致替换失败,因为 std::iterator_traits::iterator_category 是 typedef。编译器不会尝试查看 typedef 是否正确并且会接受替换。

标签: c++ templates std


【解决方案1】:

这个问题可以用cmets中的方法来展示:

#include <iterator>
#include <iostream>

template <typename T>
class IsIterator {
public:
  struct TrueValue {
  char val;
 };

 struct FalseValue {
   char val[2];
 };

template <typename U>  
 static TrueValue evaluateIsIter(typename U::iterator_category*);

 template <typename U>
 static FalseValue evaluateIsIter(...);

 static const bool value = sizeof(evaluateIsIter<T>(0)) == sizeof(TrueValue);
};


int _tmain(int argc, _TCHAR* argv[])
{
std::cout << IsIterator< int >::value << std::endl;
std::cout << IsIterator< std::iterator_traits<int> >::value << std::endl;
return 0;
 }

在 VS2005 编译器上的结果为: 0 1

由此可见,这还不足以解决问题。还是我做错了什么?

【讨论】:

    【解决方案2】:

    解决方案是这样,但缺点是自定义迭代器类必须在类内部定义 typedef,而不仅仅是专门的 std::iterator_traits 类。

    // IsIterator.cpp : Defines the entry point for the console application.
    //
    
    #include "stdafx.h"
    
    #include <iterator>
    #include <iostream>
    #include <vector>
    
    template <typename T>
    class ExtractType {
    public:
      typedef T Result;  
    };
    
    template <typename U>
    class ExtractType<std::iterator_traits<U> >
    {
    public:
      typedef U Result;
    };
    
    template <typename T>
    class IsIteratorPointer
    {
    public:
      static const bool value = false;
    };
    
    template <typename T>
    class IsIteratorPointer<T*>
    {
    public:
      static const bool value = true;
    };
    
    template <typename T>
    class IsIteratorPointer<const T*>
    {
    public:
      static const bool value = true;
    };
    
    template <typename T>
    class IsIterator {
    public:
      struct TrueValue {
        char val;
      };
    
      struct FalseValue {
        char val[2];
      };
    
      template <typename U>  
      static TrueValue evaluateIsIter(typename U::iterator_category*);
    
      template <typename U>
      static FalseValue evaluateIsIter(...);
    
      typedef typename ExtractType<T>::Result TestType;
    
      static const bool value = IsIteratorPointer<TestType>::value || sizeof(evaluateIsIter<TestType>(0)) == sizeof(TrueValue);
    };
    
    struct Foo {  
    };
    
    template <> 
    struct std::iterator_traits<Foo>
    {
      typedef random_access_iterator_tag iterator_category;
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
      std::cout << IsIterator< int >::value << std::endl;
      std::cout << IsIterator< std::iterator_traits<int> >::value << std::endl;
      std::cout << IsIterator< std::iterator_traits<int*> >::value << std::endl;
      std::cout << IsIterator< std::iterator_traits<Foo> >::value << std::endl; // Will be 0 (only drawback) - typedef must be in Foo directly
      std::cout << IsIterator< std::vector<int>::const_iterator >::value << std::endl;
    
        return 0;
    }
    

    现在问题仍然存在: 能否以某种方式消除这个缺点?

    【讨论】:

      猜你喜欢
      • 2013-09-03
      • 2017-09-06
      • 2011-08-26
      • 2020-05-08
      • 1970-01-01
      • 1970-01-01
      • 2013-12-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多