2012-05-30 12 views
10

Mam funkcję w mojej przestrzeni nazw ns, która pomaga mi drukować pojemniki STL. Na przykład:boost :: formatowanie i niestandardowe drukowanie kontenerów standardowych

template <typename T> 
std::ostream& operator<<(std::ostream& stream, const std::set<T>& set) 
{ 
    stream << "{"; 
    bool first = true; 
    for (const T& item : set) 
    { 
     if (!first) 
      stream << ", "; 
     else 
      first = false; 
     stream << item; 
    } 
    stream << "}"; 
    return stream; 
} 

Działa to doskonale nadaje się do drukowania z operator << bezpośrednio:

std::set<std::string> x = { "1", "2", "3", "4" }; 
std::cout << x << std::endl; 

Jednak użycie boost::format jest niemożliwe:

std::set<std::string> x = { "1", "2", "3", "4" }; 
boost::format("%1%") % x; 

Problem jest dość oczywista: doładowania nie ma pojęcia chciałbym, aby używał mojego niestandardowego operator << do drukowania typów, które nie mają nic wspólnego z moją przestrzenią nazw. Poza dodaniem deklaracji using do boost/format/feed_args.hpp, czy istnieje wygodny sposób, aby uzyskać boost::format poszukać mojego operator <<?

+1

zdecydowanie sugge st spojrzeć na [to pytanie] (http://stackoverflow.com/q/4850473/500104), ponieważ w zasadzie odpowiada na twoje potrzeby. Nie będę głosował, aby zamknąć jako duplikat, ponieważ twoje aktualne pytanie jest inne (o 'operatora <<'). – Xeo

+2

@Xeo: Mój rzeczywisty kod wykorzystuje bardzo podobne podejście do drukowania dowolnego pojemnika. W każdym razie problem polega nie na tym, jak wydrukować kontener za pomocą 'operatora <<", jest to, jak zrobić to samo przeciążenie pracą dla rzeczy, w których Koenig nie robi tego, co chcę. –

Odpowiedz

4

Myślę, że najczystszym sposobem jest dostarczenie cienkiego opakowania do własnej przestrzeni nazw dla każdego operatora, który ma zostać zastąpiony. W Twoim przypadku, może to być:

namespace ns 
{ 
    namespace wrappers 
    { 
     template<class T> 
     struct out 
     { 
      const std::set<T> &set; 

      out(const std::set<T> &set) : set(set) {} 

      friend std::ostream& operator<<(std::ostream& stream, const out &o) 
      { 
       stream << "{"; 
       bool first = true; 
       for (const T& item : o.set) 
       { 
        if (!first) 
         stream << ", "; 
        else 
         first = false; 
        stream << item; 
       } 
       stream << "}"; 
       return stream; 
      } 
     }; 
    } 

    template<class T> 
    wrappers::out<T> out(const std::set<T> &set) 
    { 
     return wrappers::out<T>(set); 
    } 
} 

następnie używać go tak:

std::cout << boost::format("%1%") % ns::out(x); 
+0

Jest to bardzo podobne do rozwiązania, którego używałem. Przedstawiłem również moje rozwiązanie. –

1

Można spróbować czegoś takiego:

namespace boost // or __gnu_cxx 
{ 
    using np::operator<<; 
} 
#include <boost/format/feed_args.hpp> 
0

Problemem jest, jak już wspomniano, ponieważ od ADL (odnośnika zależnej argumentów - często przypisywane Andrew Koenig, ale uważam, że nie powinien dostać całą winę) .

Nawet w twoim lokalnym kontekście nie działałby w funkcji szablonu, gdzie zamierzasz używać swojego operator<<.

Jednym z oszustw jest umieszczenie zdefiniowanego operator<< w namespace std. To jest verboten, ale może zadziałać w twoim przypadku, ale tylko wtedy, gdy zostanie użyty przed użyciem i może to być problem.

Mogą istnieć inne opcje, takie jak zdefiniowanie własnego szablonu zestawu. I eksperymentowali z

template<typename T> using Set=std::set<T>; 

ale nie mógł się rozwiązanie, które pracowały bez yuyoyuppe

using np::operator<<; 

usług.

5

Rozwiązanie I rzeczywiście udał się jest dość podobna do Answeror, ale to działa na wszystko:

namespace ns 
{ 

template <typename T> 
class FormatWrapper 
{ 
public: 
    explicit FormatWrapper(const T& x) : 
      ref(x) 
    { } 

    friend std::ostream& operator<<(std::ostream& stream, 
            const FormatWrapper<T>& self 
            ) 
    { 
     // The key is that operator<< is name lookup occurs inside of `ns`: 
     return stream << self.ref; 
    } 
private: 
    const T& ref; 
}; 

template <typename T> 
FormatWrapper<T> Formatable(const T& x) 
{ 
    return FormatWrapper<T>(x); 
} 

} 

więc użycie jest:

boost::format("%1%") % Formatable(x); 
Powiązane problemy