2016-07-25 24 views
3

在單元管理科學規劃的背景下,我管理下面的類:鐺拒絕模板`/`運營商,但GNU C++接受它

template <class UnitName> 
class Quantity 
{ 
    double value; 

public: 

    Quantity(double val = 0) : value(val) {} 

    Quantity(const Quantity &) {} 

    Quantity & operator = (const Quantity &) { return *this; } 

    double get_value() const noexcept { return value; } 

    operator double() const noexcept { return value; } 

    template <class SrcUnit> 
    Quantity(const Quantity<SrcUnit> &) 
    { 
    // here the conversion is done 
    } 

    template <class SrcUnit> 
    Quantity & operator = (const Quantity<SrcUnit> &) 
    { 
    // here the conversion is done 
    return *this; 
    } 

    template <class TgtUnit> operator TgtUnit() const 
    { 
    TgtUnit ret; 
    // here the conversion is done 
    return ret; 
    } 

    template <class U, class Ur> 
    Quantity<Ur> operator/(const Quantity<U> & rhs) const 
    { 
    return Quantity<Ur>(value/rhs.value); 
    } 
}; 

儘管該類要複雜得多,我想我把足夠的信息,以說明我的問題:

現在考慮下面的代碼片段:

struct km_h {}; 
struct Km {}; 
struct Hour {}; 

Quantity<km_h> compute_speed(const Quantity<Km> & dist, 
          const Quantity<Hour> & time) 
{ 
    Quantity<km_h> v = dist/time; 
    return v; 
} 

這些代碼是接受10編譯器,它運行良好。調用最後一個模板運算符/

但它是由clang++編譯器(V 3.8.1)與以下消息拒絕:

test-simple.cc:53:26: error: use of overloaded operator '/' is ambiguous (with operand 
     types 'const Quantity<Km>' and 'const Quantity<Hour>') 
    Quantity<km_h> v = dist/time; 
        ~~~~^~~~~ 
test-simple.cc:53:26: note: built-in candidate operator/(__int128, unsigned long long) 
test-simple.cc:53:26: note: built-in candidate operator/(unsigned long, long double) 

所以我的問題是:爲什麼clang++拒絕呢?是一個有效的代碼?或gnu c++應拒絕嗎?

在代碼有效的情況下,如何修改它以便clang++接受它?

+1

如何從表達式dist/time推導出類型'Ur'? – aschepler

+0

[OT]:您可以查看http://www.boost.org/doc/libs/1_61_0/doc/html/boost_units.html – Jarod42

+1

所有這一切歸結爲使用鑄造操作員的危險。問題是,即使代碼被接受,你確定哪一個函數或一組函數實際上被調用?程序員經常被這個問題所摧毀,他們期望有一組函數被調用,但是在其他方面正在做其他的事情。如果你擺脫了'double()'鑄造操作符,你可能沒有問題。 – PaulMcKenzie

回答

7

我相信鏗鏘是正確的拒絕你的代碼&dagger;,但GCC實際上並沒有做你想要的東西(包括disttime是隱式轉換爲double和匕首;和gcc認爲內建operator/(double, double)是最佳可行的候選人)。問題是,你寫道:

template <class U, class Ur> 
Quantity<Ur> operator/(const Quantity<U> & rhs) const 

什麼是Ur?這是一個非推導的上下文 - 所以試圖調用這個運營商只是dist/time是一個推論失敗。你的候選人從未被考慮過。爲了實際使用它,你必須明確提供Ur像這樣:

dist.operator/<Hour, km_h>(time); // explicitly providing Ur == km_h 

因爲這是可怕的,你不能有Ur推斷爲模板參數 - 你必須自己提供它的一些這兩個單元的元功能:

template <class U> 
Quantity<some_mf_t<UnitName, U>> operator/(Quantity<U> const&) const; 

some_mf_t是待定義。


&dagger;你有operator double()template <class T> operator T(),這意味着所有內置的operator/都是同樣可行的候選人(他們都是非模板,完全匹配)。

&Dagger;operator double()有點失文寫保險單位的目的,不?

+0

或者用C++ 14,他可能只能使返回類型爲'auto' – SirGuy

+0

@GuyGreer我們仍然需要計算返回類型。使用'auto'不能解決任何問題。 – Barry

+1

如果轉換爲'double'是最好的轉換序列,那麼這意味着給定'f(double,double); f(double,int);數量 a;','f(a,a)'應該選擇第一個超負荷?海灣合作委員會同意叮噹聲,它是模棱兩可的,這讓我覺得鏗鏘也是'/'操作符。 – hvd