Специализация шаблона C ++ - невозможно сопоставить определение функции - PullRequest
0 голосов
/ 19 июня 2020

Полтора дня бился головой о стену, пытаясь изучить специализацию шаблонов и std :: enable_if (). Я не что-то получаю . Я пытаюсь разрешить указание типа возвращаемого значения из метода класса на основе типа класса И пользовательской спецификации во время компиляции. Например, если тип класса целочисленный, мне может потребоваться возвращаемый тип float (или int) из метода.

Мой фактический вариант использования - это массив, для которого я усредняю ​​все значения внутри. Я мог бы даже захотеть, чтобы возвращаемое логическое значение отражало результат двоичного «голосования». Есть множество комбинаций. Должен быть способ сделать это, не создавая все перегрузки по отдельности. Мой пример кода - самый простой из возможных.

Буду благодарен за любые указатели. Как я могу сделать эту частичную специализацию, если она действительно так называется?

#include <string>

template <class T>
class Test {
public:
    Test(T val) { val_ = val; }
    template <typename U> U halve ();
private:
    T val_;
};


template<class T> template<typename U>
U Test<T>::halve() {
    throw std::invalid_argument("Cannot halve non-numeric objects");
}

template<class T> template<typename U>  //example: T=int, U=float
typename std::enable_if_t<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value, U>
Test<T>::halve() {  //error C2244 - unable to match function definition to an existing declaration
    return ((U)val_ / (U)2);
}


int main() {
    Test<int> t1(5);
    float f = t1.halve<float>();    //expect 2.5
    int i = t1.halve<int>();        //expect 2
    Test<std::string> t2((std::string)"blah");
    int t2h = t2.halve<int>();  //this will throw (by design)
    return 0;
}

Ответы [ 2 ]

1 голос
/ 19 июня 2020

Комментарий Сэма уместен - вы не можете частично специализировать функцию-член. Обходной путь - использовать enable_if_t в теле класса. Примерно так должно работать:

template <class T> class Test {
  public:
    Test(T val) { val_ = val; }
    template <typename U>
      std::enable_if_t<std::is_arithmetic<T>::value && std::is_arithmetic<U>::value, U>
      halve () {  
         return ((U)val_ / (U)2);
      }
    template <typename U>
      std::enable_if_t<!(std::is_arithmetic<T>::value && std::is_arithmetic<U>::value), U>
      halve () {  
          throw std::invalid_argument("Cannot halve non-numeric objects");
      }
  private:
    T val_;
};
0 голосов
/ 19 июня 2020

Есть гораздо более простой способ сделать это, просто объявите основную функцию с шаблоном, а затем специализируйте ее для любого типа, который вам нужен. Я добавил int и float, и он вернет правильное значение.

Передайте что-нибудь еще, и оно выдаст, потому что будет вызвана первая halve функция.

template <class T>
class Test
{
public:

    Test(T val)
    {
        val_ = val;
    }

    // Default function
    template<class MainType>
    MainType halve()
    {
        throw std::invalid_argument("Cannot halve non-numeric objects");
    }

    // Int specialization
    template<>
    int halve<int>()
    {
        return (static_cast<int>(this->val_) / static_cast<int>(2));
    }

    // Float specialization
    template<>
    float halve<float>()
    {
        return (static_cast<float>(this->val_) / static_cast<float>(2));
    }

private:

    T val_;
};

int main()
{
    Test<int> t1(5);
    float f = t1.halve<float>();    // Returns 2.5
    int i = t1.halve<int>();        // Returns 2
    void* v = t1.halve<void*>();    // Throws. Type void* is not specialized in the class
    printf("%.5f %d\n", f, i);
    getchar();
    return 0;
}
...