部分特化的默认参数

发布于 2024-11-01 10:04:41 字数 1625 浏览 2 评论 0原文

我想在用户端实现什么语法:

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和具有静态成员的包装类,但静态成员可以' t 被分配给外部变量;

更新: 实际问题是通用结构和专用结构的名称相等。我不知道如何在不重命名的情况下使其工作:

// 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
}; 

What syntax I want to achieve on user side:

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

What implementation for this I have now (not working because default parameters for partial specialization are not allowed):

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
};

I've tried with enable_if and wrapper classes that have static members, but static members can't be assigned to extern variables;

UPDATE:
The actual problem is name equality for general struct and specialized struct. I don't know how to make it work without renaming:

// 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
}; 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

_蜘蛛 2024-11-08 10:04:41

我不知道为什么你认为这是有道理的

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;
  }
};

如果您提供两个参数,则不会使用默认参数。如果您仅提供 ,则将使用默认参数并起作用。如果您只提供,默认参数也会被使用,但不起作用。

I don't know why you think that this make sense

compare<double, deps>

You cannot make this work: Template arguments cannot be values of type double (they can be an lvalue of type double, but your template requires the address of a double, so that's off).

You can use function templates to make your syntax work

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>(); 
}

Alternatively, you can use class templates if you are up for some ugly hacks

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

The default argument will not be used if you provide both arguments. If you provide only <double>, the default argument will be used and will work. If you only provide <float>, the default argument will be used too, but will not work.

羁〃客ぐ 2024-11-08 10:04:41

您需要更改拥有比较运算符的结构,以便可以专门化外部模板,请参阅: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
}

You need to change the structure which owns the comparison operator such that you can specialize the outer template, see: http://ideone.com/xqtjz

the code is:

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
}
风吹雨成花 2024-11-08 10:04:41

我会采用类似特征的方法:

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);
  }
};

然后当需要特定的 epsilon 时:

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

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

并使用它:

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

I would go with traits-like approach:

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);
  }
};

and then when specific epsilon is needed:

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

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

and use it:

Compare<float, SpecificEps>()(...);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文