2012-08-02 45 views
1

boost::units使用CRTP技術,確保獨特的模板參數

struct my_base_dimension1 : units::base_dimension<my_base_dimension1, 1> { }; // ok 
struct my_base_dimension2 : units::base_dimension<my_base_dimension2, 2> { }; // ok 
struct my_base_dimension3 : units::base_dimension<my_base_dimension3, 2> { }; // error 

我試圖理解代碼如何確保模板參數是唯一的。我不明白check_base_dimension如何最終返回一個非零值,這會觸發ordinal_has_already_been_defined<true>。我認爲它與在base_dimension重新定義有關,但我不知道如何調用friend版本。有任何想法嗎?

有問題的文件是base_dimension.hppprevent_redefinition.hpp

template<class Derived, long N, 
     class = typename detail::ordinal_has_already_been_defined< 
      check_base_dimension<Derived, N>::value 
      >::type 
     > 
class base_dimension : public ordinal<N> 
{ 
public: 
    typedef base_dimension this_type; 
    typedef list<dim<Derived,static_rational<1> >, dimensionless_type> dimension_type; 
    typedef Derived type; 

private:                               
    friend Derived* 
    check_double_register(const units::base_dimension_ordinal<N>&) 
     { return(0); } 

    friend detail::yes 
    boost_units_is_registered(const units::base_dimension_ordinal<N>&) 
     { detail::yes result; return(result); } 

    friend detail::yes 
    boost_units_is_registered(const units::base_dimension_pair<Derived, N>&) 
     { detail::yes result; return(result); } 
}; 
+0

你知道'detail :: yes'和'detail :: no'的定義在哪裏嗎?我一直試圖通讀Boost的源代碼,但我認爲我和你一樣困惑。 – KRyan 2012-08-02 22:33:36

+0

@DragoonWraith'detail :: yes'和'detail :: no'位於'prevent_redefinition.hpp'文件中。 – Arlen 2012-08-02 22:48:13

+0

所以他們是!我錯過了錯過他們的感覺。嗯......好吧,我會繼續看,如果我得到它。 – KRyan 2012-08-02 22:49:04

回答

1

啊哈,我相信我有它。

答案在本節:

  /// Register this ordinal 
     /// INTERNAL ONLY 
     friend detail::yes 
     boost_units_is_registered(const units::base_dimension_ordinal&) 
     { return(detail::yes()); } 

     /// But make sure we can identify the current instantiation! 
     /// INTERNAL ONLY 
     friend detail::yes 
     boost_units_is_registered(const units::base_dimension_pair&) 
     { return(detail::yes()); }

friend聲明表示符合這些參數的函數存在,並返回detail::yes

check_base_dimension中的enum爲給定模板實例化時,它會查找採用這兩種類型的boost_units_is_registered函數。如果不存在這些模板參數的先前實例,則它找到在prevent_redefinition.hpp中定義的函數,該函數返回detail::no,但是如果存在,則它找到匹配那些返回detail::yes的參數的函數聲明(friend)。

需要注意的是,這一切都在編譯時,而不是運行時。編譯器用戶argument-dependent lookup找到匹配的函數。該函數的結果僅取決於該函數返回的內容 - 它不需要運行或調用,它只需要一個聲明,該聲明給出了返回值的大小。因此,當編譯器找到函數時,它可以確定返回值then-and-there - 該函數實際上不需要定義。當然,如果你試圖使用它(如實際運行那樣),你會得到一個鏈接器錯誤,因爲它已被聲明但從未定義過。

因此,sizeof()在編譯時確定爲detail::yes的大小,該大小與detail::no的大小不同。因此表達式的結果是false,因此check_base_dimension::valuefalse,並且ordinal_has_already_been_defined的實例化沒有得到名爲type的成員變量。

編譯器因此將拋出一個錯誤,指出

detail::ordinal_has_already_been_defined<check_base_dimension<Derived, N>::value> does not have a member variable 'type' 

或同級。最終目標達到了:您無法使用具有相同模板參數值的類的兩個實例編譯代碼。好哇!

+0

對不起,但您還沒有說過我還不知道的任何內容,我仍然不知道'base_dimension'中重新定義的'boost_units_is_registered'是如何被調用的。是的,我知道這會讓整個事情發生作用,但是怎麼做呢?我無法直接調用它(實例化它);你會怎麼稱呼它? – Arlen 2012-08-03 04:34:08

+0

@阿倫:啊,我的歉意,那還不清楚。我已經更新了一些答案來澄清。讓我知道這是否可以解釋你的事情。 – KRyan 2012-08-04 15:54:28