2011-04-14 147 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