2011-04-14 191 views
1

我想要什麼語法實現對用戶側:默認參數

double a(1.), b(2.), deps(.1); 
bool res1 = compare<double>()(a, b);  // works with default eps 
bool res2 = compare<double, &deps>()(a, b); // works with explicitly provided eps 
float c(1.), d(1.). feps(.1); 
bool res3 = compare<float>()(c, d); // don't have default eps - must not compile 
bool res4 = compare<float, &feps>()(c, d); // works only with provided eps 

我現在(不工作,因爲偏特默認參數是不允許的)有哪些實現了這一點:

extern double eps_double; // somewhere defined and initialized 

template<typename T, const T* eps> 
struct compare { // actually inherits std::binary_function 
    bool operator()(const T& t1, const T& t2) { 
    return t1 < t2 - *eps; 
    } 
}; 
template<const double* eps = &eps_double> 
struct compare<double, eps> { // the same as in default implementation 
}; 

我試着用enable_if和包裝類有靜態成員,但靜態成員不能被分配給extern變量;

更新: 實際的問題是一般結構和專用結構的名稱相等。我不知道如何度過,即使沒有重命名工作:

// treats all explicitly passed eps and don't need default parameter 
template<typename T, const T* eps> 
struct compare_eps { // need another name! 
    bool operator()(const T& t1, const T& t2) { 
    return t1 < t2 - *eps; 
    } 
}; 
// don't need default parameter either 
// because we always know what eps to use for a concrete type 
template<typename T> 
struct compare { 
    // define nothing -> will not compile on types we don't have specialization for 
}; 
template<> 
struct compare<double> { 
    // use here eps_double hardcoded 
}; 

回答

2

我不知道爲什麼你認爲這是否有道理

compare<double, deps> 

您無法完成此工作:模板參數不能是double類型的值(它們可能是double類型的左值,但您的模板需要地址爲double,因此關閉)。

您可以使用函數模板,使你的語法工作

extern double eps_double; 

template<typename T> 
types::compare<T, &eps_double> compare(
    typename enable_if<is_same<T, double>>::type * = 0 
) { 
    return types::compare<T, &eps_double>(); 
} 

template<typename T, const T *eps> 
types::compare<T, eps> compare() { 
    return types::compare<T, eps>(); 
} 

或者,你可以使用類模板,如果你是爲某些醜陋的黑客

template<typename T, const T* eps = &eps_double> 
struct compare { 
    bool operator()(const T& t1, const T& t2) { 
    return t1 < t2 - *eps; 
    } 
}; 

默認參數將不被使用如果你提供兩個參數。如果您僅提供<double>,則將使用默認參數並且可以使用。如果您只提供<float>,則也會使用默認參數,但不起作用。

+0

對不起,這是一個錯字,正確的版本是'compare ()(a,b);'粗略。請參閱我的問題更新。 – Riga 2011-04-14 11:41:48

+0

@Johannes,你在最後一段中的含義是什麼「如果你只提供,默認參數也會被使用,但是不起作用」? – Nim 2011-04-14 12:12:20

+0

@litb我無法使用最後一種方法的原因是我的專業化不僅適用於雙層,而且還適用於其他類型。 – Riga 2011-04-14 12:13:52

1

您需要更改該公司擁有的比較操作,這樣你可以專注外模板結構,請參閱:http://ideone.com/xqtjz

代碼:

extern double eps_double; // somewhere defined and initialized 
extern double deps; // NOTE: you have to make these extern a well, else cannot work 
extern float feps; 

template<typename T> 
struct compare { 
    // this internal structure now has the operator() 
    template <const T* eps> 
    struct it 
    { 
    bool operator()(const T& t1, const T& t2) const { 
     return t1 < t2 - *eps; 
    } 
    }; 
}; 

// specialize compare for double 
template<> 
struct compare<double> 
{ 
    // here you can provide the default 
    template<const double* eps=&eps_double> 
    struct it 
    { 
    bool operator()(const double& t1, const double& t2) 
    { 
     return t1 < t2 - *eps; 
    } 
    }; 
}; 

int main(void) 
{ 
    double a(1.), b(2.); 
    bool res1 = compare<double>::it<>()(a, b);  // works with default eps 
    bool res2 = compare<double>::it<&deps>()(a, b); // works with explicitly provided eps 
    float c(1.), d(1.); 
    bool res3 = compare<float>::it<>()(c, d); // don't have default eps - will not compile 
    bool res4 = compare<float>::it<&feps>()(c, d); // works only with provided eps 
} 
+0

感謝您指出了這我無法將非外部參數作爲模板參數傳遞。這使得我所有的使用模型都不實用。也許我應該將eps作爲參數傳遞給'compare'函子。你的方法使一個聰明的東西 - 它分離的問題 - 'T'專業化和'eps'專業化,良好的慣例,謝謝! – Riga 2011-04-14 12:23:28

+0

您的方法中的問題是,不能使用compare作爲typedef,併爲所有需要封裝的比較需要的信息提供類,而用戶必須在每次調用時編寫eps。 – Riga 2011-04-14 12:33:36

+1

@里加,只有當你不使用默認的雙重eps。你可以例如'typedef compare comp_double;',然後'comp_double :: it <>(a,b);'與默認eps一起工作。你只需要提供它,當你使用一個給定的eps,但那麼你也可以typedef:'typedef typename compare :: it <&feps> comp_float;',then'comp_float()(c,d);' - 就是那個你是什​​麼意思? – Nim 2011-04-14 12:37:24

0

我會去與性狀類似的方法:

template<class T> 
struct DefaultEps; 

template<> 
struct DefaultEps<double> 
{ 
    static const double eps = 4.0; 
}; 

// may or may not be needed in .cpp 
// const double DefaultEps<double>::eps; 

template<> 
struct DefaultEps<float> 
{ 
    static const float eps = 4.0; 
}; 

// may or may not be needed in .cpp 
// const float DefaultEps<float>::eps; 

template<class T, class E = DefaultEps<T> > 
struct Compare 
{ 
    bool operator()(T const &t1, T const &t2) 
    { 
    return(t1 < t2 - E::eps); 
    } 
}; 

,然後當需要特定的ε-:

struct SpecificEps 
{ 
    static const float eps = 4.0; 
}; 

// may or may not be needed in .cpp 
// const float SpecificEps::eps; 

,並使用它:

Compare<float, SpecificEps>()(...); 
+0

hi!起初,您的代碼不會編譯,因爲標準禁止非整數變量的內聯初始化。第二,我不能將我的外部定義的常量分配給頭中的靜態成員變量。如果我只有頭文件庫,那麼我將不得不在每個上下文中將每個新eps的初始化設置爲特殊的.cpp文件(我承認它不是來自您的代碼)。第三,必須爲每個新的eps定義特徵類。您的提案需要用戶提供更多,然後提及此處提及的其他提案感謝您的時間! – Riga 2011-04-14 15:21:56

+0

有趣的,g ++ 4.4.4編譯它...我確認,但我沒有檢查它與標準。 – Tomek 2011-04-14 15:41:05

+0

使用-pedantic-errors標誌 – Riga 2011-04-14 15:59:43