2017-09-08 6 views
0

、Googleのテストでは、テンプレートメソッドPrintToを宣言します。カスタムタイプのオーバーロードも追加しました。これは、多くのQtの種類の問題を解決するだろうオーバーライド私の独自の実装をライブラリからメソッドをテンプレート

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

私の問題は、私はGoogleが提供するデフォルトのテンプレート化方法を好まないし、代わりに私はこのようにそれを実装したいということです。私はGoogleのテストコード内の実装を変更することはできません。私は自分のコードでそれを再実装する必要があります。私のテンプレートメソッドを使用して

私はこのコンパイラエラーを取得:

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は既に何千ものタイプをサポートしていますが、その機能を逃したくありません!

+0

どちらのテンプレート関数も同じシグネチャとテンプレート引数を持ちます。したがって、コンパイラはそれらを区別できません。 'template void PrintTo(const C&val、:: std :: ostream * os){...}'のような関数を宣言するとどうなりますか? – vahancho

+1

私は引数名を変更すると何か変わるとは思わない!コンパイラのエラー出力も同じように見えます。 –

+1

'void PrintTo(const QAVariant&value、:: std :: ostream * os);'暗黙の変換によって探している型の一部を取得する可能性があります。そうしないと、型ごとに別々の関数を記述する必要があります。 –

答えて

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例えばオペレータに必要な必要な機能をオーバーロードすることができ==は以下の過負荷になっている、などあなたはまた、GTESTのマニュアル詐欺であるこのguideを見て、持つことができ

#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; 
} 

EDIT:ライブラリ関数(checkEqualTo)は、この必要ですADL(Argument Dependent Lookup)を使用するために、問題の型と同じ名前空間でPrintToを定義することを含む、印刷のカスタマイズを行います。以下は

は、彼らが拡張するためのメカニズムとして想定するものである。この目的のために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)... 

また彼らのドキュメントに述べたように、あなただけの、あなたのタイプのためのオペレータ< <をオーバーロードできます。

+0

私は 'PrintTo'を自分で呼んでいません。これはテストフレームワークの一部です。私は 'ASSERT_EQ(left、right)'のようなマクロを置いて、Googleのコードのどこかで、 'left'や' right'を使って 'PrintTo'を呼び出します。 –

+0

これを解決する他の方法はありませんか?私はすべてのテストでこれらのラップメソッドを記述したくありません。我々はすでにテストのhundretsがあり、私はそれらをすべて変更したくないです。編集:私は削除されたコメントに答えたと思う... –

+0

私はどのようにASSERT_EQの問題を克服することができるかを示す私の例を変更しました –

関連する問題