Teach Google-Test how to print Eigen Matrix

后端 未结 3 1405
一向
一向 2020-12-24 13:50

Introduction

I am writing tests on Eigen matrices using Google\'s testing framework Google-Mock, as already discussed in another question.

With the followi

3条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-24 14:23

    The problems you encounter are overload resolution problems.

    google test implements a template function

    namespace testing { namespace internal {
    
    template 
    void PrintTo(const T& value, std::ostream *o) { /* do smth */ }
    
    } }
    

    The Eigen library defines a printer function that is based on derivation. Hence

    struct EigenBase { };
    std::ostream& operator<< (std::ostream& stream, const EigenBase& m) { /* do smth */ }
    
    struct Eigen : public EigenBase { };
    
    void f1() {
      Eigen e;
      std::cout << e; // works
    }
    
    void f2() {
      Eigen e;
      print_to(eigen, &std::cout); // works
    }
    

    Both do have questionable design.

    Google Test should not provide an implementation of PrintTo but should instead check at compile time whether the user provides a PrintTo and otherwise call a different default printing function PrintToDefault. The PrintTo provides is a better match than the one you provided (according to overload resolution).

    on the other hand Eigen's operator<< is based on derivation and a template function will also be preferred by overload resolution.

    Eigen could provide a CRTP base class that inherits the operator<< which a better matching type.

    What you can do is inherit from eigen and provide a CRTP overload to your inherited class avoiding the issue.

    #include 
    #include 
    
    
    class EigenBase {
    };
    
    std::ostream &operator<<(std::ostream &o, const EigenBase &r) {
        o << "operator<< EigenBase called";
        return o;
    }
    
    template 
    void print_to(const T &t, std::ostream *o) {
        *o << "Google Print To Called";
    }
    
    class EigenSub : public EigenBase {};
    
    template 
    struct StreamBase {
        typedef T value_type;
    
        // friend function is inline and static
        friend std::ostream &operator<<(std::ostream &o, const value_type &r) {
            o << "operator<< from CRTP called";
            return o;
        }
    
        friend void print_to(const value_type &t, std::ostream *o) {
            *o << "print_to from CRTP called";
    
        }
    };
    
    // this is were the magic appears, because the oeprators are actually
    // defined with signatures matching the MyEigenSub class.
    class MyEigenSub : public EigenSub, public StreamBase {
    };
    
    TEST(EigenBasePrint, t1) {
        EigenBase e;
        std::cout << e << std::endl; // works
    }
    
    TEST(EigenBasePrint, t2) {
        EigenBase e;
        print_to(e, &std::cout); // works
    }
    
    TEST(EigenSubPrint, t3) {
        EigenSub e;
        std::cout << e << std::endl; // works
    }
    
    TEST(EigenCRTPPrint, t4) {
        MyEigenSub e;
        std::cout << e << std::endl; // operator<< from CRTP called
    }
    
    TEST(EigenCRTPPrint, t5) {
        MyEigenSub e;
        print_to(e, &std::cout); // prints print_to from CRTP called
    }
    

提交回复
热议问题