Параметр по умолчанию для частичной специализации - PullRequest
1 голос
/ 14 апреля 2011

Какой синтаксис я хочу достичь на стороне пользователя:

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 и wrapper, которые имеют статические члены, но статические члены нельзя назначать внешним переменным;

UPDATE: Актуальной проблемой является равенство имен для общей структуры и специализированной структуры. Я не знаю, как заставить это работать без переименования:

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

Ответы [ 3 ]

2 голосов
/ 14 апреля 2011

Я не знаю, почему вы думаете, что это имеет смысл

compare<double, deps>

Вы не можете сделать эту работу: аргументы шаблона не могут быть значениями типа double (они могут быть lvalue типа 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>, будет использоваться аргумент по умолчанию, но он не будет работать.

1 голос
/ 14 апреля 2011

Вам нужно изменить структуру, которой принадлежит оператор сравнения, чтобы можно было специализировать внешний шаблон, см .: 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 голосов
/ 14 апреля 2011

Я бы пошел с подходом, подобным чертам:

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>()(...);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...