使用我自己的实现从库中覆盖模板化方法

时间:2017-09-08 12:19:42

标签: c++ qt templates googletest

Google测试声明模板化方法PrintTo

template <typename T>
void PrintTo(const T& value, ::std::ostream* os);

有几个没有模板的重载。我还为自定义类型添加了重载。

我的问题是我不喜欢谷歌提供的默认模板化方法,而是我想像这样实现它:

template<typename T>
void PrintTo(const T &val, ::std::ostream *os)
{
    QString str;
    QDebug(&str) << val;
    *os << qUtf8Printable(str);
}

这将解决许多Qt类型的问题。我无法改变谷歌测试代码中的实现。我需要在我自己的代码中重新实现它。

使用我的模板方法我得到了这个编译错误:

include/gtest/gtest-printers.h:707:22: error: call of overloaded ‘PrintTo(const QChar&, std::ostream*&)’ is ambiguous
     PrintTo(value, os);
                      ^
include/gtest/gtest-printers.h:707:22: note: candidates are:
include/gtest/gtest-printers.h:454:6: note: void testing::internal::PrintTo(const T&, std::ostream*) [with T = QChar; std::ostream = std::basic_ostream<char>]
 void PrintTo(const T& value, ::std::ostream* os) {
      ^
In file included from tstgoogletest.cpp:51:0:
googletestqttypes.h:24:6: note: void PrintTo(const T&, std::ostream*) [with T = QChar; std::ostream = std::basic_ostream<char>]
 void PrintTo(const T &val, ::std::ostream *os)
      ^

是否可以使用我的自定义实现“重载”模板化方法而不列出我想要使用的每种类型?

QDebug已经支持了数千种类型,我不想错过这个功能!

1 个答案:

答案 0 :(得分:1)

问题是编译器无法执行重载,因为您的函数签名与google完全相同。您可以创建一个新类型来强制重载,例如:

#include <iostream>

// Google version
template <class T> 
void print(const T& value, std::ostream& os) {
  os << "Google print: " << value << std::endl;
}

// My wrapper type

template <class T>
struct PrintWrap {
    const T& value_;

    PrintWrap(const T& value): value_(value){}
};

template <class T>
PrintWrap<T> printWrap(const T& value) {
    return PrintWrap<T>(value);
}


template <class T>
void print(const PrintWrap<T>& printWrap, std::ostream& os) {
  os << "My special print: " << printWrap.value_ << std::endl;
}

int main() {
  std::string value = "Hallo world";
  print(printWrap(value), std::cout);   

  // your code goes here
  return 0;
}

如果你无法控制调用代码,你可以重载printWrap中所需的必要函数,例如operator ==在下面重载,因为库函数(checkEqualTo)需要这样:

#include <iostream>

// Google version
template <class T> 
void print(const T& value, std::ostream& os) {
  os << "Google print: " << value << std::endl;
}

// My wrapper type 
// :NOTE Overload what is required by Google, in this
// case lets assume operator== as example
template <class T>
struct PrintWrap {
    const T& value_;
    PrintWrap(const T& value): value_(value){}

  friend bool operator==(const PrintWrap& lhs, const PrintWrap& rhs) {
   return lhs.value_ == rhs.value_;
  }
};

template <class T>
PrintWrap<T> printWrap(const T& value) {
    return PrintWrap<T>(value);
}


template <class T>
void print(const PrintWrap<T>& printWrap, std::ostream& os) {
  os << "My special print: " << printWrap.value_ << std::endl;
}

template <class T>
bool checkEqualTo(const T& lhs, const T& rhs) {
  if (lhs == rhs) return true;
  print(lhs, std::cout);
  print(rhs, std::cout);
  return false;
}

// Google code...
#define CHECK_EQUAL(x,y) checkEqualTo(x,y)

int main() {
  std::string value = "Hallo world";
  CHECK_EQUAL(printWrap(value), printWrap(value));

  return 0;
}

修改

您还可以查看此guide,这是GTest关于打印自定义的文档,其中涉及将PrintTo定义在与所讨论的类型相同的命名空间中,以便使用ADL(Argument Dependent Lookup)。 / p>

以下是为此目的使用ADL的一个例子,这是他们设想的扩展机制,它会接缝:

#include <iostream>
#include <cassert>

// Google version template <class T>  
void print(const T& value, std::ostream& os) {
  os << "Google print: " << value << std::endl; 
}

namespace custom {

template <class T>
struct Printable : T
{
  template <class...Args>
  Printable(Args&&... args) 
  : T(std::forward<Args>(args)...)
  { }
};

template <class T>
void print(const Printable<T>& value, std::ostream& os) {
  os << "My special print: " << value << std::endl;
}

} //custom

int main() {
  custom::Printable<std::string> x = "my string";
  custom::Printable<std::string> y = "my other string";

  assert(! (x == y));

  //found by ADL      
  print(x, std::cout); 
  return 0;
}

在上面,与参数相同的命名空间中的函数声明具有查找优先级,因此不存在歧义。您不需要使用Printable(可能有更好的完整实现)。您可以根据需要为每种类型打印。

请注意,上面的代码是我的示例。 GTest要求重载为:

void PrintTo(const Bar& bar, ::std::ostream* os)...

此外,您可以重载运算符&lt;&lt;对于您的类型,如文档中所述。