为什么 std::function 不能相等比较?

发布于 2024-09-17 11:22:14 字数 1401 浏览 6 评论 0原文

这个问题也适用于 boost::functionstd::tr1::function

std::function 不可进行等式比较:

#include <functional>
void foo() { }

int main() {
    std::function<void()> f(foo), g(foo);
    bool are_equal(f == g); // Error:  f and g are not equality comparable
}

在 C++11 中,operator==operator!= 重载根本不存在。在早期的 C++11 草案中,重载被声明为已删除,并带有注释 (N3092 §20.8.14.2):

// deleted overloads close possible hole in the type system

它没有说明“类型系统中可能的漏洞”是什么。在 TR1 和 Boost 中,声明了重载但未定义。 TR1 规范注释 (N1836 §3.7.2.6):

这些成员函数应保持未定义。

[注意:类似布尔的转换打开了一个漏洞,可以通过 ==!= 比较两个函数实例。这些未定义的 void 运算符封闭了漏洞并确保编译时错误。 —尾注]

我对“漏洞”的理解是,如果我们有一个 bool 转换函数,则该转换可以用于相等比较(以及其他情况下):

struct S {
    operator bool() { return false; }
};

int main() {
    S a, b;
    bool are_equal(a == b); // Uses operator bool on a and b!  Oh no!
}

我的印象是,C++03 中的 safe-bool 习惯用法和 C++11 中显式转换函数的使用是为了避免这个“漏洞”。 Boost 和 TR1 都在 function 中使用 safe-bool 习惯用法,并且 C++11 使 bool 转换函数显式化。

作为同时具有这两种功能的类的示例,std::shared_ptr 都具有显式 bool 转换函数并且可以进行相等比较。

为什么 std::function 不能进行相等比较?什么是“类型系统中可能的漏洞?”它与 std::shared_ptr 有何不同?

This question also applies to boost::function and std::tr1::function.

std::function is not equality comparable:

#include <functional>
void foo() { }

int main() {
    std::function<void()> f(foo), g(foo);
    bool are_equal(f == g); // Error:  f and g are not equality comparable
}

In C++11, the operator== and operator!= overloads just don't exist. In an early C++11 draft, the overloads were declared as deleted with the comment (N3092 §20.8.14.2):

// deleted overloads close possible hole in the type system

It does not say what the "possible hole in the type system" is. In TR1 and Boost, the overloads are declared but not defined. The TR1 specification comments (N1836 §3.7.2.6):

These member functions shall be left undefined.

[Note: the boolean-like conversion opens a loophole whereby two function instances can be compared via == or !=. These undefined void operators close the loophole and ensure a compile-time error. —end note]

My understanding of the "loophole" is that if we have a bool conversion function, that conversion may be used in equality comparisons (and in other circumstances):

struct S {
    operator bool() { return false; }
};

int main() {
    S a, b;
    bool are_equal(a == b); // Uses operator bool on a and b!  Oh no!
}

I was under the impression that the safe-bool idiom in C++03 and the use of an explicit conversion function in C++11 was used to avoid this "loophole." Boost and TR1 both use the safe-bool idiom in function and C++11 makes the bool conversion function explicit.

As an example of a class that has both, std::shared_ptr both has an explicit bool conversion function and is equality comparable.

Why is std::function not equality comparable? What is the "possible hole in the type system?" How is it different from std::shared_ptr?

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

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

发布评论

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

评论(7

小苏打饼 2024-09-24 11:22:14

为什么是std::function 不具有可比性吗?

std::function 是任意可调用类型的包装器,因此为了实现相等比较,您必须要求所有可调用类型都是相等比较的,这给任何实现者带来了负担一个函数对象。即使这样,您也会得到一个狭窄的相等概念,因为如果(例如)它们是通过以不同顺序绑定参数来构造的,则等效函数将比较不相等。我相信在一般情况下不可能测试等效性。

“类型系统中可能存在的漏洞是什么?”

我猜这意味着删除运算符并且确定使用它们永远不会给出有效的代码比证明在某些先前未发现的极端情况下不可能发生不需要的隐式转换更容易。

它与std::shared_ptr有什么不同?


std::shared_ptr 具有明确定义的相等语义;两个指针相等当且仅当它们都为空或都非空且指向同一个对象时。

Why is std::function not equality comparable?

std::function is a wrapper for arbitrary callable types, so in order to implement equality comparison at all, you'd have to require that all callable types be equality-comparible, placing a burden on anyone implementing a function object. Even then, you'd get a narrow concept of equality, as equivalent functions would compare unequal if (for example) they were constructed by binding arguments in a different order. I believe it's impossible to test for equivalence in the general case.

What is the "possible hole in the type system?"

I would guess this means it's easier to delete the operators, and know for certain that using them will never give valid code, than to prove there's no possibility of unwanted implicit conversions occurring in some previously undiscovered corner case.

How is it different from std::shared_ptr?

std::shared_ptr has well-defined equality semantics; two pointers are equal if and only if they are either both empty, or both non-empty and pointing to the same object.

故笙诉离歌 2024-09-24 11:22:14

我可能是错的,但我认为 std::function 对象的相等性在一般意义上是不可解决的。例如:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <cstdio>

void f() {
    printf("hello\n");
}

int main() {
    boost::function<void()> f1 = f;
    boost::function<void()> f2 = boost::bind(f);

    f1();
    f2();
}

f1f2 相等吗?如果我添加任意数量的函数对象,这些函数对象以各种方式简单地相互包装,最终归结为对 f 的调用...仍然相等,该怎么办?

I may be wrong, but I think that equality of std::function objects is unfortunately not solvable in the generic sense. For example:

#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <cstdio>

void f() {
    printf("hello\n");
}

int main() {
    boost::function<void()> f1 = f;
    boost::function<void()> f2 = boost::bind(f);

    f1();
    f2();
}

are f1 and f2 equal? What if I add an arbitrary number of function objects which simply wrap each other in various ways which eventually boils down to a call to f... still equal?

太阳公公是暖光 2024-09-24 11:22:14

为什么 std::function 不能进行相等比较?

我认为主要原因是,如果是的话,那么它就不能与非相等比较类型一起使用,即使从未执行相等比较。

即执行比较的代码应该尽早实例化 - 当可调用对象存储到 std::function 中时,例如在构造函数或赋值运算符之一中。

这样的限制会大大缩小应用范围,对于“通用多态函数包装器”来说显然是不可接受的。


值得注意的是,可以 boost::function 与可调用对象进行比较(但不与另一个 boost::function

函数对象包装器可以通过 ==!= 与可以存储在包装器中的任何函数对象进行比较。

这是可能的,因为执行此类比较的函数是根据已知的操作数类型在比较点实例化的。

此外,std::function有一个< strong>target模板成员函数,可以用来进行类似的比较。事实上 boost::function 的比较运算符是 根据target成员函数实现

因此,不存在阻碍 function_comparable 实现的技术障碍。


在答案中存在常见的“一般不可能”模式:

  • 即使这样,您也会得到一个狭义的相等概念,因为如果(例如)它们是通过以不同顺序绑定参数来构造的,则等效函数将比较不相等。我相信在一般情况下不可能测试等效性。

  • <块引用>

    我可能是错的,但不幸的是,我认为 std::function 对象的相等性在一般意义上是不可解决的。

  • <块引用>

    因为图灵机的等价性是不可判定的。给定两个不同的函数对象,您不可能确定它们是否计算相同的函数。 [该答案已被删除]

我完全不同意这一点:执行比较本身不是 std::function 的工作;它的工作只是重定向请求以与底层对象进行比较 - 仅此而已。

如果底层对象类型没有定义比较 - 这将是一个编译错误;无论如何,都不需要 std::function 来推导比较算法。

如果底层对象类型定义了比较,但工作错误,或者有一些不寻常的语义 - 这也不是 std::function 本身的问题,而是底层类型的问题。


可以基于std::function实现function_comparable

这是一个概念验证:

template<typename Callback,typename Function> inline
bool func_compare(const Function &lhs,const Function &rhs)
{
    typedef typename conditional
    <
        is_function<Callback>::value,
        typename add_pointer<Callback>::type,
        Callback
    >::type request_type;

    if (const request_type *lhs_internal = lhs.template target<request_type>())
        if (const request_type *rhs_internal = rhs.template target<request_type>())
            return *rhs_internal == *lhs_internal;
    return false;
}

#if USE_VARIADIC_TEMPLATES
    #define FUNC_SIG_TYPES typename ...Args
    #define FUNC_SIG_TYPES_PASS Args...
#else
    #define FUNC_SIG_TYPES typename function_signature
    #define FUNC_SIG_TYPES_PASS function_signature
#endif

template<FUNC_SIG_TYPES>
struct function_comparable: function<FUNC_SIG_TYPES_PASS>
{
    typedef function<FUNC_SIG_TYPES_PASS> Function;
    bool (*type_holder)(const Function &,const Function &);
public:
    function_comparable() {}
    template<typename Func> function_comparable(Func f)
        : Function(f), type_holder(func_compare<Func,Function>)
    {
    }
    template<typename Func> function_comparable &operator=(Func f)
    {
        Function::operator=(f);
        type_holder=func_compare<Func,Function>;
        return *this;
    }
    friend bool operator==(const Function &lhs,const function_comparable &rhs)
    {
        return rhs.type_holder(lhs,rhs);
    }
    friend bool operator==(const function_comparable &lhs,const Function &rhs)
    {
        return rhs==lhs;
    }
    friend void swap(function_comparable &lhs,function_comparable &rhs)// noexcept
    {
        lhs.swap(rhs);
        lhs.type_holder.swap(rhs.type_holder);
    }
};

有一个很好的属性 - function_comparable 可以与 std::function也是。

例如,假设我们有 std::functions 向量,并且我们希望为用户提供 register_callbackunregister_callback 函数。仅 unregister_callback 参数需要使用 function_comparable

void register_callback(std::function<function_signature> callback);
void unregister_callback(function_comparable<function_signature> callback);

现场演示 < strong>Ideone

演示源代码:

//             Copyright Evgeny Panasyuk 2012.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <type_traits>
#include <functional>
#include <algorithm>
#include <stdexcept>
#include <iostream>
#include <typeinfo>
#include <utility>
#include <ostream>
#include <vector>
#include <string>

using namespace std;

// _____________________________Implementation__________________________________________

#define USE_VARIADIC_TEMPLATES 0

template<typename Callback,typename Function> inline
bool func_compare(const Function &lhs,const Function &rhs)
{
    typedef typename conditional
    <
        is_function<Callback>::value,
        typename add_pointer<Callback>::type,
        Callback
    >::type request_type;

    if (const request_type *lhs_internal = lhs.template target<request_type>())
        if (const request_type *rhs_internal = rhs.template target<request_type>())
            return *rhs_internal == *lhs_internal;
    return false;
}

#if USE_VARIADIC_TEMPLATES
    #define FUNC_SIG_TYPES typename ...Args
    #define FUNC_SIG_TYPES_PASS Args...
#else
    #define FUNC_SIG_TYPES typename function_signature
    #define FUNC_SIG_TYPES_PASS function_signature
#endif

template<FUNC_SIG_TYPES>
struct function_comparable: function<FUNC_SIG_TYPES_PASS>
{
    typedef function<FUNC_SIG_TYPES_PASS> Function;
    bool (*type_holder)(const Function &,const Function &);
public:
    function_comparable() {}
    template<typename Func> function_comparable(Func f)
        : Function(f), type_holder(func_compare<Func,Function>)
    {
    }
    template<typename Func> function_comparable &operator=(Func f)
    {
        Function::operator=(f);
        type_holder=func_compare<Func,Function>;
        return *this;
    }
    friend bool operator==(const Function &lhs,const function_comparable &rhs)
    {
        return rhs.type_holder(lhs,rhs);
    }
    friend bool operator==(const function_comparable &lhs,const Function &rhs)
    {
        return rhs==lhs;
    }
    // ...
    friend void swap(function_comparable &lhs,function_comparable &rhs)// noexcept
    {
        lhs.swap(rhs);
        lhs.type_holder.swap(rhs.type_holder);
    }
};

// ________________________________Example______________________________________________

typedef void (function_signature)();

void func1()
{
    cout << "func1" << endl;
}

void func3()
{
    cout << "func3" << endl;
}

class func2
{
    int data;
public:
    explicit func2(int n) : data(n) {}
    friend bool operator==(const func2 &lhs,const func2 &rhs)
    {
        return lhs.data==rhs.data;
    }
    void operator()()
    {
        cout << "func2, data=" << data << endl;
    }
};
struct Caller
{
    template<typename Func>
    void operator()(Func f)
    {
        f();
    }
};
class Callbacks
{
    vector<function<function_signature>> v;
public:
    void register_callback_comparator(function_comparable<function_signature> callback)
    {
        v.push_back(callback);
    }
    void register_callback(function<function_signature> callback)
    {
        v.push_back(callback);
    }
    void unregister_callback(function_comparable<function_signature> callback)
    {
        auto it=find(v.begin(),v.end(),callback);
        if(it!=v.end())
            v.erase(it);
        else
            throw runtime_error("not found");
    }
    void call_all()
    {
        for_each(v.begin(),v.end(),Caller());
        cout << string(16,'_') << endl;
    }
};

int main()
{
    Callbacks cb;
    function_comparable<function_signature> f;
    f=func1;
    cb.register_callback_comparator(f);

    cb.register_callback(func2(1));
    cb.register_callback(func2(2));
    cb.register_callback(func3);
    cb.call_all();

    cb.unregister_callback(func2(2));
    cb.call_all();
    cb.unregister_callback(func1);
    cb.call_all();
}

输出为:

func1
func2, data=1
func2, data=2
func3
________________
func1
func2, data=1
func3
________________
func2, data=1
func3
________________

PS 似乎在 std::type_index,可以实现类似于function_comparable类的东西,它也支持排序(即std ::less)甚至是散列。不仅可以在不同类型之间排序,还可以在同一类型内排序(这需要类型的支持,例如 LessThanComparable)。

Why is std::function not equality comparable?

I think main reason is that if it were, then it couldn't be used with non equality comparable types, even if equality comparison is never performed.

I.e. code that performs comparison should be instantiated early - at the time when a callable object is stored into std::function, for instance in one of the constructors or assignment operators.

Such a limitation would greatly narrow the scope of application, and obviously not be acceptable for a "general-purpose polymorphic function wrapper".


It is important to note that it is possible to compare a boost::function with a callable object (but not with another boost::function)

Function object wrappers can be compared via == or != against any function object that can be stored within the wrapper.

This is possible, because function that performs such comparison is instantiated at point of comparison, based on known operand types.

Moreover, std::function has a target template member function, which can be used to perform similar comparison. In fact boost::function's comparison operators are implemented in terms of target member function.

So, there are no technical barriers which block implementation of function_comparable.


Among answers there is common "impossible in general" pattern:

  • Even then, you'd get a narrow concept of equality, as equivalent functions would compare unequal if (for example) they were constructed by binding arguments in a different order. I believe it's impossible to test for equivalence in the general case.

  • I may be wrong, but I think that equality is of std::function objects is unfortunately not solvable in the generic sense.

  • Because the equivalence of Turing machines is undecidable. Given two different function objects, you cannot possibly determine if they compute the same function or not. [That answer was deleted]

I completely disagree with this: it is not the job of std::function to perform comparison itself; its job is just to redirect request to comparison to underlying objects - that's all.

If underlying object type does not define comparison - it will be a compilation error; in any case, std::function is not required to deduce a comparison algorithm.

If the underlying object type defines comparison, but which works wrongly, or has some unusual semantic - it is not the problem of std::function itself either, but it is problem of the underlying type.


It is possible to implement function_comparable based on std::function.

Here is a proof-of-concept:

template<typename Callback,typename Function> inline
bool func_compare(const Function &lhs,const Function &rhs)
{
    typedef typename conditional
    <
        is_function<Callback>::value,
        typename add_pointer<Callback>::type,
        Callback
    >::type request_type;

    if (const request_type *lhs_internal = lhs.template target<request_type>())
        if (const request_type *rhs_internal = rhs.template target<request_type>())
            return *rhs_internal == *lhs_internal;
    return false;
}

#if USE_VARIADIC_TEMPLATES
    #define FUNC_SIG_TYPES typename ...Args
    #define FUNC_SIG_TYPES_PASS Args...
#else
    #define FUNC_SIG_TYPES typename function_signature
    #define FUNC_SIG_TYPES_PASS function_signature
#endif

template<FUNC_SIG_TYPES>
struct function_comparable: function<FUNC_SIG_TYPES_PASS>
{
    typedef function<FUNC_SIG_TYPES_PASS> Function;
    bool (*type_holder)(const Function &,const Function &);
public:
    function_comparable() {}
    template<typename Func> function_comparable(Func f)
        : Function(f), type_holder(func_compare<Func,Function>)
    {
    }
    template<typename Func> function_comparable &operator=(Func f)
    {
        Function::operator=(f);
        type_holder=func_compare<Func,Function>;
        return *this;
    }
    friend bool operator==(const Function &lhs,const function_comparable &rhs)
    {
        return rhs.type_holder(lhs,rhs);
    }
    friend bool operator==(const function_comparable &lhs,const Function &rhs)
    {
        return rhs==lhs;
    }
    friend void swap(function_comparable &lhs,function_comparable &rhs)// noexcept
    {
        lhs.swap(rhs);
        lhs.type_holder.swap(rhs.type_holder);
    }
};

There is a nice property - function_comparable can be compared against std::function too.

For instance, let's say we have vector of std::functions, and we want to give users register_callback and unregister_callback functions. Use of function_comparable is required only for unregister_callback parameter:

void register_callback(std::function<function_signature> callback);
void unregister_callback(function_comparable<function_signature> callback);

Live demo at Ideone

Source code of demo:

//             Copyright Evgeny Panasyuk 2012.
// Distributed under the Boost Software License, Version 1.0.
//    (See accompanying file LICENSE_1_0.txt or copy at
//          http://www.boost.org/LICENSE_1_0.txt)

#include <type_traits>
#include <functional>
#include <algorithm>
#include <stdexcept>
#include <iostream>
#include <typeinfo>
#include <utility>
#include <ostream>
#include <vector>
#include <string>

using namespace std;

// _____________________________Implementation__________________________________________

#define USE_VARIADIC_TEMPLATES 0

template<typename Callback,typename Function> inline
bool func_compare(const Function &lhs,const Function &rhs)
{
    typedef typename conditional
    <
        is_function<Callback>::value,
        typename add_pointer<Callback>::type,
        Callback
    >::type request_type;

    if (const request_type *lhs_internal = lhs.template target<request_type>())
        if (const request_type *rhs_internal = rhs.template target<request_type>())
            return *rhs_internal == *lhs_internal;
    return false;
}

#if USE_VARIADIC_TEMPLATES
    #define FUNC_SIG_TYPES typename ...Args
    #define FUNC_SIG_TYPES_PASS Args...
#else
    #define FUNC_SIG_TYPES typename function_signature
    #define FUNC_SIG_TYPES_PASS function_signature
#endif

template<FUNC_SIG_TYPES>
struct function_comparable: function<FUNC_SIG_TYPES_PASS>
{
    typedef function<FUNC_SIG_TYPES_PASS> Function;
    bool (*type_holder)(const Function &,const Function &);
public:
    function_comparable() {}
    template<typename Func> function_comparable(Func f)
        : Function(f), type_holder(func_compare<Func,Function>)
    {
    }
    template<typename Func> function_comparable &operator=(Func f)
    {
        Function::operator=(f);
        type_holder=func_compare<Func,Function>;
        return *this;
    }
    friend bool operator==(const Function &lhs,const function_comparable &rhs)
    {
        return rhs.type_holder(lhs,rhs);
    }
    friend bool operator==(const function_comparable &lhs,const Function &rhs)
    {
        return rhs==lhs;
    }
    // ...
    friend void swap(function_comparable &lhs,function_comparable &rhs)// noexcept
    {
        lhs.swap(rhs);
        lhs.type_holder.swap(rhs.type_holder);
    }
};

// ________________________________Example______________________________________________

typedef void (function_signature)();

void func1()
{
    cout << "func1" << endl;
}

void func3()
{
    cout << "func3" << endl;
}

class func2
{
    int data;
public:
    explicit func2(int n) : data(n) {}
    friend bool operator==(const func2 &lhs,const func2 &rhs)
    {
        return lhs.data==rhs.data;
    }
    void operator()()
    {
        cout << "func2, data=" << data << endl;
    }
};
struct Caller
{
    template<typename Func>
    void operator()(Func f)
    {
        f();
    }
};
class Callbacks
{
    vector<function<function_signature>> v;
public:
    void register_callback_comparator(function_comparable<function_signature> callback)
    {
        v.push_back(callback);
    }
    void register_callback(function<function_signature> callback)
    {
        v.push_back(callback);
    }
    void unregister_callback(function_comparable<function_signature> callback)
    {
        auto it=find(v.begin(),v.end(),callback);
        if(it!=v.end())
            v.erase(it);
        else
            throw runtime_error("not found");
    }
    void call_all()
    {
        for_each(v.begin(),v.end(),Caller());
        cout << string(16,'_') << endl;
    }
};

int main()
{
    Callbacks cb;
    function_comparable<function_signature> f;
    f=func1;
    cb.register_callback_comparator(f);

    cb.register_callback(func2(1));
    cb.register_callback(func2(2));
    cb.register_callback(func3);
    cb.call_all();

    cb.unregister_callback(func2(2));
    cb.call_all();
    cb.unregister_callback(func1);
    cb.call_all();
}

Output is:

func1
func2, data=1
func2, data=2
func3
________________
func1
func2, data=1
func3
________________
func2, data=1
func3
________________

P.S. It seems that with help of std::type_index, it is possible to implement something similar to function_comparable class, which also supports ordering (i.e. std::less) or even hashing. Not only ordering between different types, but also ordering within same type (this requires support from types, like LessThanComparable).

难理解 2024-09-24 11:22:14

根据 http://www.open- std.org/jtc1/sc22/wg21/docs/lwg-active.html#1240

这里的主要评论是
std::function 的历史,其中
与 N1402 一起推出。在那期间
时间没有显式转换函数
存在,并且“safe-bool”习语
(基于指向成员的指针)是
流行技术。唯一的
这个习语的缺点是
给定两个类型为 f1f2 的对象
std::function,表达式

f1 == f2;

格式良好,只是因为
内置 operator== 用于指针
会员在一次后被考虑
用户定义的转换。为了解决这个问题,
未定义的重载集
添加了比较功能,例如
重载决议更喜欢
那些最终导致链接错误的。
删除的新语言设施
功能提供了更好的
修复此问题的诊断机制
问题。

在 C++11 中,删除的函数被认为是多余的,因为引入了显式转换运算符,因此它们可能会在 C++11 中删除。

这个问题的中心点是,
与更换
通过显式转换实现 safe-bool 习惯用法
bool,原始的“类型中的漏洞”
系统”已不存在并且
因此该评论是错误的
多余的函数定义
也应该被删除。

至于为什么不能比较 std::function 对象,可能是因为它们可能保存全局​​/静态函数、成员函数、仿函数等,并且要执行此操作 std::函数“擦除”有关底层类型的一些信息。因此,实现相等运算符可能是不可行的。

According to http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#1240:

The leading comment here is part of
the history of std::function, which
was introduced with N1402. During that
time no explicit conversion functions
existed, and the "safe-bool" idiom
(based on pointers-to-member) was a
popular technique. The only
disadvantage of this idiom was that
given two objects f1 and f2 of type
std::function, the expression

f1 == f2;

was well-formed, just because the
built-in operator== for pointer to
member was considered after a single
user-defined conversion. To fix this,
an overload set of undefined
comparison functions was added, such
that overload resolution would prefer
those ending up in a linkage error.
The new language facility of deleted
functions provided a much better
diagnostic mechanism to fix this
issue.

In C++11, the deleted functions are considered superfluous with the introduction of explicit conversion operators, so they will probably be removed for C++11.

The central point of this issue is,
that with the replacement of the
safe-bool idiom by explicit conversion
to bool, the original "hole in the type
system" does no longer exist and
therefore the comment is wrong and the
superfluous function definitions
should be removed as well.

As for why you can't compare std::function objects, it's probably because they can possibly hold global/static functions, member functions, functors, etc, and to do that std::function "erases" some information about the underlying type. Implementing an equality operator would probably not be feasible because of that.

北斗星光 2024-09-24 11:22:14

其实,你可以比较目标。它可能有效取决于您想要从比较中得到什么。

这里的代码带有不等式,但您可以看到它是如何工作的:

template <class Function>
struct Comparator
{
    bool operator()(const Function& f1, const Function& f2) const
    {
        auto ptr1 = f1.target<Function>();
        auto ptr2 = f2.target<Function>();
        return ptr1 < ptr2;
    }
};

typedef function<void(void)> Function;

set<Function, Comparator<Function>> setOfFunc;

void f11() {}

int _tmain(int argc, _TCHAR* argv[])
{
    cout << "was inserted - " << setOfFunc.insert(bind(&f11)).second << endl;  // 1 - inserted
    cout << "was inserted - " << setOfFunc.insert(f11).second << endl;         // 0 - not inserted
    cout << "# of deleted is " << setOfFunc.erase(f11) << endl;

    return 0;
}

Ups,它仅从 C++11 起有效。

Actually, you can compare targets. It may work depends of what you want from comparison.

Here the code with inequality, but you can see how it works:

template <class Function>
struct Comparator
{
    bool operator()(const Function& f1, const Function& f2) const
    {
        auto ptr1 = f1.target<Function>();
        auto ptr2 = f2.target<Function>();
        return ptr1 < ptr2;
    }
};

typedef function<void(void)> Function;

set<Function, Comparator<Function>> setOfFunc;

void f11() {}

int _tmain(int argc, _TCHAR* argv[])
{
    cout << "was inserted - " << setOfFunc.insert(bind(&f11)).second << endl;  // 1 - inserted
    cout << "was inserted - " << setOfFunc.insert(f11).second << endl;         // 0 - not inserted
    cout << "# of deleted is " << setOfFunc.erase(f11) << endl;

    return 0;
}

Ups, it is only valid since C++11.

提笔书几行 2024-09-24 11:22:14

尝试下面的方法怎么样,这对于测试模板很有效。

if (std::is_same<T1, T2>::value)
{
    ...
}

How about trying something like the following, this works well for testing templates.

if (std::is_same<T1, T2>::value)
{
    ...
}
沙沙粒小 2024-09-24 11:22:14

至少可以做的是,如果 std::function 保存用于绑定到字符串的函数的地址并改为使用字符串比较。

the least that could be done is if std::function saves the address of the function used for binding to a string and used string comparison instead.

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