Pourquoi est std::function et non l'égalité comparable?
Je pense que la raison principale est que si il serait, alors il ne peut pas être utilisé avec la non égalité de types comparables, même si la comparaison d'égalité n'est jamais effectuée.
I. e. le code qui effectue la comparaison doit être instancié tôt - au moment où appelable objet est stocké dans std::function, par exemple dans l'un des constructeurs ou des opérateurs d'affectation.
Une telle limitation serait grandement réduire la portée de l'application, et évidemment pas acceptable "à des fins générales fonction polymorphe wrapper".
Il est improtant à noter qu'il est possible de comparer les boost::function avec l'objet appelable (mais pas avec un boost::function)
La fonction de l'objet wrappers peuvent être comparées via == ou != contre toute de la fonction de l'objet qui peut être stocké à l'intérieur de l'emballage.
C'est possible, parce que la fonction qui effectue la comparaison instantiniated à un point de comparaison, en se fondant sur le savoir type d'opérande.
En outre, std::function a cible modèle de fonction de membre, qui peut être utilisé pour effectuer la comparaison similaire. En fait, boost::fonction de comparaison les opérateurs sont mis en œuvre en termes de cible de la fonction membre.
Donc, il n'y a pas d'obstacles techniques qui bloquent implementantion de function_comparable.
Parmi les réponses, il est commun "impossible en général" pattern:
Même alors, vous obtiendrez un concept étroit de l'égalité, comme l'équivalent des fonctions serait de comparer l'inégalité (par exemple) si elles ont été construites par la liaison des arguments dans un ordre différent. Je crois qu'il est impossible de tester l'équivalence dans le cas général.
J'ai peut-être tort, mais je pense que l'égalité est de std::function objets est, malheureusement, n'est pas soluble dans le sens générique.
Parce que l'équivalence des machines de turing est indécidable. Étant donné deux functionobjects, vous ne pouvez pas éventuellement de déterminer si ils calculent la même fonction ou pas. [Cette réponse a été supprimée]
Je suis complètement en désaccord avec ceci: il n'est pas d'emplois de std::function pour effectuer la comparaison elle-même, c'est du boulot, c'est juste pour rediriger la demande à la comparaison d'objets sous-jacents, c'est tout.
Si le sous-jacent type d'objet ne définit pas de la comparaison, il sera erreur de compilation dans tous les cas, std::function n'est pas nécessaire d'en déduire l'algorithme de comparaison.
Si le sous-jacent type d'objet définit la comparaison, mais qui fonctionne mal, ou avoir un peu inhabituel sémantique, il n'est pas problème de std::function elle-même, mais c'est le problème de type sous-jacent.
Il est possible de mettre en œuvre function_comparable basé sur std::function.
Ici en est la preuve-de-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);
}
};
Il y a une belle propriété - function_comparable peut être comparé à des std::function trop.
Par exemple, disons que nous avons vecteur de std::function de l', et nous voulons donner de l'utilisateur register_callback et unregister_callback fonctions. À l'aide de function_comparable est requise uniquement pour les unregister_callback paramètre:
void register_callback(std::function<function_signature> callback);
void unregister_callback(function_comparable<function_signature> callback);
Démonstration en direct à Ideone
Le code Source de la démo:
// 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();
}
La sortie est:
func1
func2, data=1
func2, data=2
func3
________________
func1
func2, data=1
func3
________________
func2, data=1
func3
________________
P. S. Il semble que, avec l'aide de std::type_index il est possible de mettre en œuvre similaire à function_comparable classe, qui prend également en charge la commande(c'est à dire de moins en moins) ou même de hachage. Mais pas seulement de la commande entre les différents types, mais aussi de la commande au sein d'un même type (ce qui nécessite la prise en charge de types, comme LessThanComparable).