代码之家  ›  专栏  ›  技术社区  ›  Mykola Golubyev

STL算法的C++“智能”谓词

  •  2
  • Mykola Golubyev  · 技术社区  · 16 年前

    我需要为stl算法设计谓词,如find\u if、count\u if。

    namespace lib
    {
        struct Finder
        {
            Finder( const std::string& name ):
                name_( name )
            {
            }
    
            template< typename TElement >
            bool operator( const TElement& element )
            {
                return element.isPresent( name_ );
            }
    
            /* template< typename TElement >
            bool operator( const TElement& element )
            {
                const Data& data = element.getData();
                return data.isPresent( name_ );
            }*/ 
        };
    }
    

    但我需要它有不同的操作符(),这取决于远程通信中某些特定方法的存在。比如,如果它有“getData”,我想检查数据,如果没有,我会做一些其他的动作。

    我知道SFINAE。但是我在这个项目上没有boost::的支持。 所以,要么有一些简单的实现模板“has_方法”,要么你知道一些其他的设计解决方案。

    我不能指向特定的类型,也不能简单地重载,因为我想把这个谓词放在一个项目库中,它不知道使用“getData”方法的那些特定类。

    谢谢

    4 回复  |  直到 16 年前
        1
  •  3
  •   Shane Powell    16 年前

    为什么要使用模板方法呢?如果有很多类类型,只需使用您想要基于的特定类或公共基类即可。

    例如

    struct Finder
    {
        Finder( const std::string& name ):
            name_( name )
        {
        }
    
        bool operator( const IsPresentBaseClass& element )
        {
            return element.isPresent( name_ );
        }
    
        bool operator( const GetDataBaseClass& element )
        {
            const Data& data = element.getData();
            return data.isPresent( name_ );
        } 
     };
    

    如果这种模式经常发生在不同的类类型中,并且您在使用谓词之前就知道这些类型,那么您可以对谓词本身进行模板化。

    例如

    template<class T1, class T2>
    struct Finder
    {
        Finder( const std::string& name ):
            name_( name )
        {
        }
    
        bool operator( const T1& element )
        {
            return element.isPresent( name_ );
        }
    
        bool operator( const T2& element )
        {
            const Data& data = element.getData();
            return data.isPresent( name_ );
        } 
     };
    

    或者你可以使用的另一种方法是使用某种类别特征来保存信息。

    例如

    struct UseIsPresent
    {
        template<class T>
        static bool CompareElement( const T& element, const std::string& name )
        {
            return element.isPresent( name );
        }
    };
    
    struct UseGetData
    {
        template<class T>
        static bool CompareElement( const T& element, const std::string& name )
        {
            const Data& data = element.getData();
            return data.isPresent( name );
        } 
    };
    
    // default to using the isPresent method
    template <class T>
    struct FinderTraits
    {
        typedef UseIsPresent FinderMethodType;
    };
    
    // either list the classes that use GetData method
    // or use a common base class type, e.g. UseGetData
    template <>
    struct FinderTraits<UseGetData>
    {
        typedef UseGetData FinderMethodType;
    };
    
    struct Finder
    {
        Finder( const std::string& name )
        : name_( name )
        {
        }
    
        template<class T>
        bool operator()( const T& element )
        {
            return FinderTraits<T>::FinderMethodType::CompareElement<T>(element, name_);
        }
    
        std::string name_;
    };
    

    所有这些方法的缺点是,在某些时候,您需要知道类型,以便能够将它们拆分为要使用的方法。

        2
  •  1
  •   dirkgently    16 年前

    你可以看看 Veldhuizen's homepage switch 样板您可能可以使用此选项来选择确切的运算符?

        3
  •  0
  •   Benoît photo_tom    16 年前

    让您的类型从“功能类型”(例如类型“has_function1”)派生,该类型将用作java接口,您有机会,因为SFINAE可以用于测试一种类型是否可以转换为另一种类型。

    如果你感兴趣,我可以调查一下,给你一个更详细的答案。

    我知道你说过你没有可用的Boost库,但是有没有什么东西阻止你获得获得Boost::可用的几个文件?没有什么特别的东西需要编译!

        4
  •  0
  •   MSalters    16 年前

    提振不是魔法;使用SFINAE相当简单:

        template< typename TElement >
        bool operator( const TElement& element, ... )
        {
            return element.isPresent( name_ );
        }
    
        template< typename TElement >
        bool operator( const TElement& element, const Data& data = element.getData())
        {
            return data.isPresent( name_ );
        }
    

    如果没有编译,SFINAE将删除第二个重载。重载解析将选择第二个,如果它编译自。。。这是一场更糟糕的比赛。