C++ “聪明” stl算法的谓词

发布于 2024-07-14 12:27:54 字数 949 浏览 8 评论 0原文

我需要为 stl 算法设计谓词,例如 find_if、count_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_ );
        }*/ 
    };
}

但我需要它根据 TElement 中某些特定方法的存在具有不同的运算符 () 。 就像如果它有“getData”我想检查该数据,如果没有我会做一些其他操作。

我知道 SFINAE。 但我的项目上没有 boost:: 。 因此,要么有一些模板“has_method”的简单实现,要么您知道其他一些设计解决方案。

我无法指向特定类型并简单地重载,因为我想将此谓词放入项目库之一,该项目库不知道具有“getData”方法的那些特定类。

只要没有命名空间,具有类特征的解决方案就很好。 谓词查找器位于“lib”命名空间中,带有“getData”的类位于“program”命名空间中。

谢谢。

I need to designe predicate for stl algorithms such as find_if, count_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_ );
        }*/ 
    };
}

But I need it to have different operators () according to presence of some certain methods in TElement. Like if it has "getData" I'd like to check that data and if it hasn't I'd do some other actions.

I am aware of SFINAE. But I don't have boost:: on the project.
So either there is some easy implementation of template "has_method" or you know some other design solution.

I can't point specific types and simply overload because I'd like to put this Predicate to the one of the project library, which don't know about those specific classes with "getData" method.

Solution with class traits are good as far as there is no namespaces. Predicate Finder in in "lib" namespace and class with "getData" is in "program" namespace.

Thanks.

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

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

发布评论

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

评论(4

没有伤那来痛 2024-07-21 12:27:54

为什么要使用模板方法? 只需使用您想要作为其基础的特定类,或者如果有很多类类型,则使用公共基类。

例如,

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_;
};

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

Why use template mathods at all? Just use the specific class that you want to base it on or a common base classes if there are lots of class types.

e.g.

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_ );
    } 
 };

If this pattern happens a lot with different class types and you know the types before using the predicate you could template the predicate itself.

e.g.

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_ );
    } 
 };

Or another approach you could use is to use some sort of class traits to hold the information.

e.g.

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_;
};

The downsides of all these methods is that at some point you need to know the types to be able to split them up into which method to use.

唱一曲作罢 2024-07-21 12:27:54

您可以查看 Veldhuizen 的主页 switch 模板。 您也许可以用它来选择确切的运算符?

You can have a look at Veldhuizen's homepage for the switch template. You can probably use this to choose the exact operator?

夜无邪 2024-07-21 12:27:54

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

如果您有兴趣,我可以研究一下并给您更详细的答案。

编辑:
我知道您说过您没有可用的 Boost 库,但是有什么因素阻止您获取 boost::is_convertible 工作所需的几个文件吗? 不会有什么特别需要编译的!

Have your types derive from "functionality types" (eg a type "has_function1") that will work as java interfaces and you have a chance, because SFINAE can be used to test if one type can be converted into another one.

If you're interested, i can look into it and give you a more detailed answer.

EDIT :
I know you said you didn't have Boost libraries available, but is there anything preventing you from getting the few files that are needed to get boost::is_convertible working ? There would not be anything in particular to compile !

铃予 2024-07-21 12:27:54

Boost 并不是魔法,而是魔法。 使用 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 将删除第二个重载。 重载解析将选择第二个,如果它确实编译的话,因为...是一个更差的匹配。

Boost is not magic; using SFINAE is fairly straightforward:

    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 will remove the second overload if it doesn't compile. Overload resolution will pick the second, if it does compile since ... is a worse match.

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