2017-01-11 2 views
3

J'essaye d'écrire un operator| pour ma classe de modèle boo et tout fonctionne bien jusqu'à ce que la classe de modèle soit un type de gamme boost - comme dans l'exemple un boost::range::filter_range - adl préfère le boost::range_detail::operator|(SinglePassRange& r, const replace_holder<T>) au local.Pourquoi adl préfère le 'boost :: range_detail :: operator |' sur l'opérateur local |

Quelqu'un peut-il expliquer pourquoi adl préfère la surcharge de la booster cet espace de noms détaillé sur l'espace de noms local?

#include <vector> 
#include <boost/range/adaptors.hpp> 

namespace local 
{ 
    template<typename T> 
    struct boo {}; 

    // this overload is not prefered when T is a boost::range::xxx_range 
    template<typename T, typename U> 
    auto operator|(boo<T>, U) 
    { 
     return false; 
    } 

    void finds_local_operator_overload() 
    { 
     std::vector<int> xs; 

     // works like expected and calls local::operator| 
     auto f = boo<decltype(xs)>{} | xs; 
    } 

    void prefers_boost_range_detail_replaced_operator_overload_instead_of_local_operator() 
    { 
     std::vector<int> xs; 
     // compiler error because it tries to call 'boost::range_detail::operator|' 
     auto filtered = xs | boost::adaptors::filtered([](auto &&x){ return x % 2; }); 
     auto f = boo<decltype(filtered)>{} | xs; 
    } 

}

erreur clang (rapports de MSVC presque les mêmes):

/xxx/../../thirdparty/boost/1.60.0/dist/boost/range/value_type.hpp:26:70: error: no type named 'type' in 
     'boost::range_iterator<local::boo<boost::range_detail::filtered_range<(lambda at 
     /xxx/Tests.cpp:221:49), std::vector<int, std::allocator<int> > > >, void>' 
    struct range_value : iterator_value< typename range_iterator<T>::type > 
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~ 
/xxx/../../thirdparty/boost/1.60.0/dist/boost/range/adaptor/replaced.hpp:122:40: note: in instantiation of template class 
     'boost::range_value<local::boo<boost::range_detail::filtered_range<(lambda at 
     /xxx/Tests.cpp:221:49), std::vector<int, std::allocator<int> > > > >' requested 
     here 
       BOOST_DEDUCED_TYPENAME range_value<SinglePassRange>::type>& f) 
            ^
/xxx/Tests.cpp:222:37: note: while substituting deduced template arguments into 
     function template 'operator|' [with SinglePassRange = local::boo<boost::range_detail::filtered_range<(lambda at 
     /xxx/Tests.cpp:221:49), std::vector<int, std::allocator<int> > > >] 
     auto f = boo<decltype(filtered)>{} | xs; 
+1

Les deux opérateurs doivent être pris en compte. mais je suppose que le boost est plus spécialisé que le tien. – Jarod42

+0

Pourquoi les fonctions du modèle 'boost :: range_detail :: replace_holder' sont-elles prises en compte? Il n'y a aucun argument qui ouvre l'espace de noms boost. Il n'y a que le modèle 'T' qui provient de l'espace de nommage boost. Et s'il y a une bonne raison de le prendre en compte, pourquoi les autres fonctions du gabarit Booster de gamme ne sont-elles pas prises en compte? – TimW

Répondre

2

Selon les règles de ADL, espace de noms et les classes ajoutés dans l'ensemble pour les surcharges pour boo<decltype(filtered)>{} | xs sont local (pour boo), boost::range_detail (pour decltype(filtered)) et std (pour std::vector<int>xs).

Nous avons en particularité:

(Comme vous attendez, vos années à local

template<typename T, typename U> auto operator|(boo<T>, U); 

et)

une problématique boost::range_detail:

template <class SinglePassRange> 
replaced_range<const SinglePassRange> 
operator|(
    const SinglePassRange&, 
    const replace_holder<typename range_value<SinglePassRange>::type>&); 

Nous avons donc le non déduit range_value<boo<decltype(filtered)>>::type qui provoque une erreur dure. (La méthode n'est malheureusement pas compatible SFINAE pour être retirée du jeu de surcharge).

Une erreur se produit avant overload_resolution.

+0

Il semble y avoir une certaine ambiguïté dans la 'spécialisation de modèle de classe' cppreference documentée: dans ce cas, 'boo ' n'est clairement pas une spécialisation, c'est un template de classe _instantiation_. – xtofl

+2

@xtofl c'est une spécialisation (bien, * simple-template-id * qui nomme une spécification), son utilisation dans un programme peut provoquer une instanciation (implicite) selon 14.7.1 [temp.inst] – Cubbi