Cela est apparu lorsque je recherchais un bogue dans le wrapper boost::fusion::fused
lors de l'utilisation de decltype. Le problème semble être qu'un decltype invalide est une erreur de compilation, même si l'instanciation de modèle qui le requiert ne sera pas utilisée, et je ne peux pas comprendre comment contourner cela pour créer un wrapper de fonction générique.Des encapsuleurs de fonctions génériques en C++ sont-ils possibles?
Voilà ma tentative de l'emballage unique argument:
#include <utility>
#include <type_traits>
template <class T>
typename std::add_rvalue_reference<T>::type declval();
template <class Fn, class Arg>
struct get_return_type
{
typedef decltype(declval<Fn>()(declval<Arg>())) type;
};
template <class Fn>
struct wrapper
{
explicit wrapper(Fn fn) : fn(fn) {}
Fn fn;
template <class Arg>
typename get_return_type<Fn,Arg&&>::type
operator()(Arg&& arg)
{
return fn(std::forward<Arg>(arg));
}
template <class Arg>
typename get_return_type<const Fn,Arg&&>::type
operator()(Arg&& arg)
{
return fn(std::forward<Arg>(arg));
}
};
Le problème est, cela ne fonctionne pas pour les cas où les arguments à la version non-const ne sont pas convertibles aux arguments de la const version. Par exemple:
#include <iostream>
struct x {};
struct y {};
struct foo
{
void operator()(x) { std::cout << "void operator()(x)" << std::endl; }
void operator()(y) const { std::cout << "void operator()(y) const" << std::endl; }
};
int main()
{
wrapper<foo> b = wrapper<foo>(foo());
b(x()); // fail
}
Il me semble que l'échec de l'expression decltype causée par void operator()(y) const
doit simplement donner lieu à cette fonction étant retirée en raison de SFINAE.
ne devrait pas être là un retour dans vos opérateurs pour l'emballage? –
@VJovic Oups! Merci, je les ai ajoutés maintenant. – Ayjay
Le deuxième opérateur() dans l'encapsuleur doit également être const. Quel compilateur? Quelle est l'erreur? Pour g ++ 4.6.1, je reçois une erreur bizarre: 'no match for call to (const foo) (x)' –