Ошибка GCC с SFINAE в конце типа возврата - PullRequest
1 голос
/ 07 июня 2019

В моем коде ниже я намерен определить Weighted<T>::operator+=, только если параметр шаблона T имеет operator+= и operator*=.Он отлично работает на MSVC14, но GCC (протестированный с 6.3.0) завершается ошибкой с ошибкой «нет совпадения для« operator * = »» в указанном месте (когда T не имеет operator*=).

template<typename T>
struct Weighted {
    double weight;
    T value;

    // ...

    // weighted mean
    template<typename U=T>
    auto operator+=(const Weighted<U>& other) -> decltype(value += other.value, value*=1.0, *this) {
// ***COMPILE ERROR*** ---------------------------------------------------->    ~~~~~^~~~~

        value *= weight;
        value += other.weight*other.value;
        weight += other.weight;
        value /= weight;
        return *this;
    }

    // scale weight
    Weighted<T>& operator*=(double multiplier) {
        weight *= multiplier;
        return *this;
    }
};

Как мне это сделать?Если проблема связана с версией компилятора, существует ли простой способ избежать обновления компилятора?

Ответы [ 2 ]

0 голосов
/ 07 июня 2019

Я бы сделал так:

#include  <experimental/type_traits>

using std::experimental::is_detected;

template <typename T, typename U>
using plus_equal_t = decltype(std::declval<T&>() += std::declval<U>());

template <typename T, typename U>
using time_equal_t = decltype(std::declval<T&>() += std::declval<U>());

// Define traits
template <typename T, typename U>
using has_plus_equal = is_detected<plus_equal_t, T, U>;

template <typename T, typename U>
using has_time_equal = is_detected<time_equal_t, T, U>;



template<typename T>
struct Weighted {
    double weight;
    T value;

    // ...

    // weighted mean
    template<typename U=T,
             std::enable_if_t<has_plus_equal<U, U>::value
                              && has_time_equal<U, double>::value, int> = 0>
    Weighted& operator+=(const Weighted<T>& other) {
        value *= weight;
        value += other.weight*other.value;
        weight += other.weight;
        value /= weight;
        return *this;
    }
    // ...
};

А в C ++ 2a упростите его до:

Weighted& operator+=(const Weighted<T>& other)
    requires(has_plus_equal<T, T>::value && has_time_equal<T, double>::value)
{ /*..*/ }
0 голосов
/ 07 июня 2019
template<typename U=T, typename = std::enable_if_t<std::is_same<U,T>::value>>
auto operator+=(const Weighted<U>& other) -> decltype(value += other.value, std::declval<U&>()*=1.0, *this) {
    // ...
}

Также добавлена ​​проверка в первой строке, чтобы ограничить совпадение U и T.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...