2017-03-13 17 views
4

私はchrono_literalsを使用して構築できるようにするために、std :: chrono :: durationを取るコンストラクタを持つクラステンプレートを持っています。今、私は非メンバ演算子のオーバーロードを定義しようとしているが、私はそれが持続コンストラクタで動作させることはできません。クラステンプレートの非メンバー演算子オーバーロードを定義する方法は?

main.cpp:34:12: error: no match for ‘operator==’ (operand types are ‘MyClass<0>’ and ‘std::chrono::nanoseconds {aka std::chrono::duration<long int, std::ratio<1l, 1000000000l> >}’) 
    if (m1 == 10ns) 
     ~~~^~~~~~~ 
main.cpp:23:6: note: candidate: template<int n> bool operator==(MyClass<n>, MyClass<n>) 
bool operator == (MyClass<n> lhs, MyClass<n> rhs) 
     ^~~~~~~~ 
main.cpp:23:6: note: template argument deduction/substitution failed: 
main.cpp:34:15: note: ‘std::chrono::duration<long int, std::ratio<1l, 1000000000l> >’ is not derived from ‘MyClass<n>’ 
    if (m1 == 10ns) 
       ^~~~ 

#include <chrono> 
#include <iostream> 

using namespace std; 

template <int n> struct MyClass { 
    MyClass() = default; 

    template <typename REP, typename PERIOD> 
    constexpr MyClass(const std::chrono::duration<REP, PERIOD> &d) noexcept 
     : num(d.count()) {} 

    int num = n; 
}; 

template <int n> bool operator==(MyClass<n> lhs, MyClass<n> rhs) { 
    return lhs.num == rhs.num; 
} 

int main(int argc, char *argv[]) { 
    using namespace std::literals::chrono_literals; 

    MyClass<0> m1(10ns); 

    if (m1 == 10ns) 
    cout << "Yay!" << endl; 
    return 0; 
} 

gccが私の過負荷を拒否するため、このエラーを与えています

この作業を行う方法はありますか?

+1

これには、テンプレート控除、ユーザー定義変換、および過負荷解決の特定の組み合わせが必要です。そして、このコードが必要とする順序では起こりません。 –

答えて

8

簡単な方法は、クラス内の関数を置くことです:

template <int n> struct MyClass { 
    MyClass() = default; 

    template <typename REP, typename PERIOD> 
    constexpr MyClass(const std::chrono::duration<REP, PERIOD> &d) noexcept 
     : num(d.count()) {} 

    friend bool operator==(MyClass lhs, MyClass rhs) { return lhs.num == rhs.num; } 


    int num = n; 
}; 

Demo

+0

これは良い解決策です、ありがとう!関数を次のようにしたくない場合はどうすればよいですか?1.宣言されたフレンド、2.クラス定義の中で定義されているか?私はこれが "より単純な"方法か_onlyなのか、私が求めていると思いますか? – dcmm88

+2

@ dcmm88定義上、フレンド関数は、クラス外で宣言した場合と同じように、非メンバ関数です。また、ボーナスとして、プライベートメンバーにアクセスすることを含め、あなたのクラスであなたが望むことをすることができます。この場合、友人を使うことの欠点はありません。しかし、クラスの外でfriend関数を定義することはできますが、それでもそれを宣言する必要があります。 –

+2

@GuillaumeRacicot私は実際には(内側を宣言し、外側を定義する)動作しないと思います。私はテンプレートを使って、それをどのように外部に定義しますか?それから私は元の問題に戻っていますか? – dcmm88

5

これは動作しません:

if (m1 == 10ns) 

我々はoperator==上で検索をやっているときので、 MyClass<0>std::chrono::duration<???, std::nano>の間にある唯一の演算子は、

です。
template <int n> 
bool operator==(MyClass<n> lhs, MyClass<n> rhs); 

これが一致しない - 10nsはどのnためMyClass<n>ないので、テンプレート控除は失敗します。あなたが既に持っているオペレータに加えて

template <int n, class R, class P> bool operator==(duration<R,P>, MyClass<n>); 

:両方向の

template <int n, class R, class P> bool operator==(MyClass<n>, duration<R,P>); 

:非会員の等価演算子を作成するには、に対してどの期間を一致させる必要があります。それはうまくいくことがあり、必要な場合もあります。

Jarod42が示唆するように、より簡単な方法は、operator==をメンバー以外の友人として宣言することです。これが機能する理由は、メンバー以外の関数が関数テンプレートの場合、その友人はではなく、です。だから、m1 == 10nsの検索が機能見つかっ:

bool operator==(MyClass<0>, MyClass<0>); 

10nsは、このコンテキストで許可されているMyClass<0>、に変換可能であるが、これは動作します。その変換は非常に安いので、そこに心配はありません。そして、あなたはただ一つの関数を書く必要があります。

+0

または、2つのパラメータの1つを、推定されていないコンテキストでラップします。 –