Résolution de surcharge de signature «manuelle»

Je veux créer un object semblable à std::function qui puisse gérer le stockage de plusieurs surcharges.

La syntaxe ressemble à ceci: my_function .

Ou, plus explicitement:

 template struct type_list {}; template struct my_function { std::tuple< std::function... > m_functions; typedef type_list sig_list; template typename pick_overload_signature< sig_list, type_list >::return_value operator()( Args&&... args ) { return get<pick_overload_signature< sig_list, type_list >::index>(m_functions)(std::forward(args)...); } }; 

Ma question: comment devrais-je écrire pick_overload_signatures ?

Voici le travail que j’ai fait dessus:

Mon penchant serait d’écrire un ordre partiel sur les signatures de fonctions par rapport à un ensemble d’arguments donné, puis de sortinger la liste des types de signatures de fonctions, puis d’obtenir le meilleur (avec éventuellement une assertion à la compilation, selon laquelle le meilleur est unique). Pour réussir cela, je devrais avoir un ordre partiel solide (en ce qui concerne un ensemble d’arguments transmis) sur les signatures de fonction …

13.3.3.1 me dit comment déterminer s’il existe une conversion valide. Je peux sortingcher pour cela en utilisant le compilateur pour effectuer une conversion pour moi et utiliser SFINAE pour détecter si cela s’est produit pour un argument donné transmis et la signature de l’une des “surcharges”.

13.3.3.2 me dit comment commander ces conversions. Ici, je dois détecter si une séquence de conversion est définie par l’utilisateur ou une séquence standard. Je ne sais pas comment faire la distinction entre les deux.

Peut-être que je peux utiliser la classe traits pour détecter l’existence de séquences de conversions définies par l’utilisateur. Vérifiez l’existence de &S::operator D() et de &D::D(S const&) et de &D::D(S) et de &D::D(S&&) ou quelque chose du genre.

has_user_defined_conversion::value , has_standard_conversion::value , etc.?

Cette approche fonctionnera-t-elle, est-ce que quelqu’un l’a déjà fait ou est-ce que quelqu’un en a déjà fait partie?

Résultat des réponses

 #include  #include  #include  #include  #include  #include  // Packaged list of types: template struct type_list { template<templateclass target> struct apply { typedef target type; }; template struct append { typedef type_list type; }; template struct prepend { typedef type_list type; }; }; template<templateclass mapper, typename list> struct map_types { typedef type_list type; }; template<templateclass mapper, typename T0, typename... Ts> struct map_types<mapper, type_list> { typedef typename map_types<mapper, type_list>::type tail; typedef typename tail::template prepend< typename mapper::type >::type type; }; template<templateclass mapper, typename list> using MapTypes = typename map_types::type; template<templateclass temp> struct apply_template_to { template struct action { typedef temp type; }; }; template<template class temp, typename list> struct apply_to_each:map_types< apply_template_to::template action, list > {}; template<template class temp, typename list> using ApplyToEach = typename apply_to_each::type; template struct nth_type {}; template struct nth_type<n, type_list>:nth_type<n-1, type_list> {}; template struct nth_type<0, type_list> { typedef first type; }; template using NthType = typename nth_type::type; // func data template struct unpacked_func { typedef R result_type; typedef type_list args_type; typedef unpacked_func unpacked_type; template<templateclass target> struct apply { typedef target type; }; }; namespace unpack_details { // Extracting basic function properties: template struct unpack_func {}; template struct unpack_func { typedef unpacked_func type; }; template struct unpack_func< unpacked_func >: unpack_func {}; } template using FuncUnpack = typename unpack_details::unpack_func::type; template struct func_props:func_props<FuncUnpack> {}; template struct func_props<unpacked_func>: unpacked_func {}; template using FuncResult = typename func_props::result_type; template using FuncArgs = typename func_props::args_type; template struct make_func_ptr:make_func_ptr<FuncUnpack> {}; template struct make_func_ptr< unpacked_func > { typedef R(*type)(Args...); }; template using MakeFuncPtr = typename make_func_ptr::type; // Marking a type up with an index: template struct indexed_type { typedef R type; enum { value = i }; }; // Sequences of size_t: template struct seq {}; template struct make_seq: make_seq {}; template struct make_seq { typedef seq type; }; template using MakeSeq = typename make_seq::type; namespace overload_details { template struct indexed_linear_signatures {}; template struct signature_generator {}; template struct signature_generator<unpacked_func> { R operator()(Args...); // no impl }; template struct indexed_retval {}; template struct indexed_retval< unpacked_func, i > { typedef unpacked_func<indexed_type, Args...> type; }; template using IndexRetval = typename indexed_retval::type; void test1() { typedef overload_details::IndexRetval< FuncUnpack, 0 > indexed; indexed::apply::type test = []()->indexed_type {return indexed_type();}; } template struct indexed_linear_signatures: signature_generator<IndexRetval<FuncUnpack,n>>, indexed_linear_signatures {}; template struct extract_index {}; template struct extract_index<indexed_type> { enum {value = i}; }; template using Decay = typename std::decay::type; template struct get_overload_index { enum{ value = extract_index< Decay<decltype( std::declval()(std::declval()...) )> >::value }; }; template struct get_overload {}; template struct get_overload<type_list, type_list> { typedef indexed_linear_signatures sig_index; enum { index = get_overload_index::value }; typedef FuncUnpack< NthType<index, type_list > > unpacked_sig; }; template using GetOverloadSig = typename get_overload::unpacked_sig; } template struct pick_overload_signature { enum{ index = overload_details::get_overload::index }; typedef overload_details::GetOverloadSig unpacked_sig; }; #include  void test1() { typedef type_list overloads; typedef type_list args; typedef pick_overload_signature result; std::cout << result::index << " should be 0\n"; typedef type_list args2; typedef pick_overload_signature result2; std::cout << result2::index << " should be 1\n"; // ; typedef ApplyToEach::apply::type functions; typedef std::tuple< std::function, std::function > functions0; std::cout << std::is_same() << " should be true\n"; functions funcs{ [](int) { std::cout << "int!" << "\n"; }, [](double) { std::cout << "double!" << "\n"; } }; std::get(funcs)(0); } template struct my_function { typedef type_list signatures; typedef std::tuple< std::function... > func_tuple; func_tuple functions; template explicit my_function(Funcs&&... funcs): functions( std::forward(funcs)... ) {} template auto operator()(Args&&... args) const -> typename overload_details::GetOverloadSig< signatures, type_list >::result_type { return std::get< pick_overload_signature< signatures, type_list >::index >(functions)(std::forward(args)...); } // copy/assign boilerplate template my_function( my_function const& o ): functions( o.functions ) {} template my_function( my_function && o ): functions( std::move(o.functions) ) {} template my_function& operator=( my_function const& o ) { functions = o.functions; return *this; } template my_function& operator=( my_function && o ) { functions = std::move(o.functions); return *this; } }; struct printer { template void operator()( T const& t ) { std::cout << t << "\n"; } }; void print(int x) { std::cout << "int is " << x << "\n"; } void print(std::string s) { std::cout << "string is " << s << "\n"; } void test2() { my_function funcs{ [](int x){ std::cout << "int is " << x << "\n";}, [](std::string s){ std::cout << "string is " << s << "\n";} }; std::cout << "test2\n"; funcs("hello"); funcs(0); my_function funcs2{ printer(), printer() }; funcs2("hello"); funcs2(12.7); // doesn't work: /* my_function funcs3{ print, print }; */ } void test3() { } int main() { test1(); test2(); test3(); } 

N’est pas fait, mais est utilisable.

Merci a tous!

je suis sûr que c’est faisable à votre façon, mais peut-être serez-vous satisfait de celui-ci https://gist.github.com/dabrahams/3779345

 template struct overloaded; template struct overloaded : F1, overloaded::type { typedef overloaded type; overloaded(F1 head, Fs...tail) : F1(head), overloaded::type(tail...) {} using F1::operator(); using overloaded::type::operator(); }; template struct overloaded : F { typedef F type; using F::operator(); }; template typename overloaded::type overload(Fs...x) { return overloaded(x...); } auto f = overload( [](int x) { return x+1; }, [](char const* y) { return y + 1; }, [](int* y) { return y; }); 

Je pense que vous pouvez utiliser quelque chose comme ces caractéristiques … Mais si vous voulez résoudre le problème de surcharge de manière complète, vous avez besoin de plus de code http://fr.cppreference.com/w/cpp/language/implicit_cast

 #include  template struct is_constructible { template static auto test(C*) -> decltype(C(std::declval()), std::true_type()); template static std::false_type test(...); static const bool value = std::is_class::value && std::is_same(0))>::value; }; template struct has_conversion_operator { static std::true_type test(D d); template static auto test(C* c) -> decltype(test(*c)); template static std::false_type test(...); static const bool value = std::is_class::value && !is_constructible::value && std::is_same(0))>::value; }; template struct is_standard_convertible : std::integral_constant::value && !is_constructible::value && std::is_convertible::value> { }; template struct is_user_convertible : std::integral_constant::value || is_constructible::value> { }; 

et implémentez ce que vous voulez: vérifier d’abord que les signatures sont standard_convertible sinon vérifier que les signatures sont user_convertible.