Предотвращение коллизий перегрузки оператора шаблона для float и non float в первом аргументе оператора

У меня есть ситуация, когда мой оператор модуля шаблона хорошо работает между типами с плавающей запятой и целыми числами. Насколько я помню, есть способ заставить его выбрать более конкретный из более широкого диапазона, но я не могу найти или вспомнить, как это сделать.

В основном у меня есть 2 метода, которые конфликтуют (ошибка переопределения).

То, что я пытаюсь сделать, это использовать специализированную перегрузку оператора модуля, когда его тип (T_COORDS) является плавающим, более широкий, когда он не плавающий.

Специализированный (обратите внимание, что он использует математическую функцию fmod):

template <size_t N
    , enable_if_t<N != 0 && N <= C_COORDS*N_COORDS && N % C_COORDS == 0, bool> = false>
friend Coords operator % (const Coords<float,C_COORDS,N_COORDS>& coords0, const auto (& coords1)[N])
{
  Coords<float,C_COORDS,N_COORDS> result = coords0;
  for (int i=0; i < C_COORDS*N_COORDS; i++)
      result.coords[i] = fmod(result.coords[i], coords1[i%N]);
  return result;
}

Более широкий (обратите внимание, что он использует стандартный модуль с плавающей запятой):

template <std::size_t N
    , std::enable_if_t<N != 0 && N <= C_COORDS*N_COORDS && N % C_COORDS == 0
    , bool> = false>
friend Coords operator % (const Coords<T_COORDS,C_COORDS,N_COORDS>& coords0, const auto (& coords1)[N])
{
  Coords<T_COORDS,C_COORDS,N_COORDS> result = coords0;
  for (int i=0; i < C_COORDS*N_COORDS; i++)
      result.coords[i] %= coords1[i%N];
  return result;
}

Эти перегрузки заключены в определение класса Template:

template <class T_COORDS, size_t C_COORDS, size_t N_COORDS>
class Coords {
public:

  T_COORDS coords[C_COORDS*N_COORDS];

  // (body in here)

};

person Ismael Harun    schedule 30.05.2020    source источник


Ответы (3)


T_COORDS — это параметр шаблона класса, а не параметр шаблона функции, что означает, что он не имеет значения для частичного упорядочения, поскольку более общая функция в любом случае создается с помощью T_COORDS=float, и поэтому она точно такая же, как float. Однако вы можете отключить эту функцию от разрешения перегрузки, используя тот факт, что она уже имеет некоторые enable_if условия, которые зависят от непосредственного контекста:

template <std::size_t N
        , std::enable_if_t<N != 0 && N <= C_COORDS*N_COORDS && N % C_COORDS == 0
                           && !std::is_same<T_COORDS, float>{}
                           // ~~~~~~~~~~~~^
        , bool> = false>
friend Coords operator %(const Coords<T_COORDS, C_COORDS, N_COORDS>& coords0
                       , const auto (& coords1)[N]);
person Piotr Skotnicki    schedule 30.05.2020
comment
Что ж, это работает. Спасибо. Я просто сейчас думаю о двойниках. Я думаю, что я могу идти об этом неправильно. Пока я использую ваш ответ. - person Ismael Harun; 30.05.2020

Я не мог понять вашу логику, но если вы хотите, чтобы поведение вашей функции изменялось в зависимости от типа double или нет, вы можете использовать что-то вроде следующего.

#include <type_traits>
#include <iostream>
template <class T>
void func(){
    constexpr static bool isFloat = std::is_floating_point<T>::value;//static in classes
    if (isFloat) std::cout << "f\n";//u can use fmod() here
    else std::cout << "i\n";//use regular % here
}
int main(){
    func<int>();
    func<double>();
}
person asmmo    schedule 30.05.2020
comment
Это очень хорошо и обрабатывает как поплавки, так и двойники. Спасибо. Но я бы предпочел просто использовать перегрузку метода, наиболее подходящую для внутреннего класса (T_COORDS), а затем выполнить условное выполнение, если я правильно понимаю. Я думаю, что лучше всего изучить шаблоны, чтобы лучше понять, как их использовать. - person Ismael Harun; 30.05.2020
comment
Да, я удалил кучу кода для публикации, потому что думал, что это поможет сосредоточиться, но я вижу, что это только вызывает загадку. Спасибо за отзыв, я буду публиковать более полные примеры/код в будущем. - person Ismael Harun; 31.05.2020

Я бы оставил только одну из этих перегрузок, но изменил бы цикл for на это:

for (int i=0; i < C_COORDS*N_COORDS; i++)
    result.coords[i] = my_mod(result.coords[i], coords1[i%N]);

После определения my_mod следующим образом (во внешней области):

template <typename T>
T my_mod(const T& x, const T& y) { return x % y; }

float my_mod(float x, float y) { return fmod(x, y); }
// maybe define it for double as well
person John Zwinck    schedule 30.05.2020