【问题标题】:GCC error with SFINAE in trailing return type尾随返回类型中带有 SFINAE 的 GCC 错误
【发布时间】:2019-10-22 16:32:29
【问题描述】:

在下面的代码中,我的意图是仅当模板参数T 具有operator+=operator*= 时才定义Weighted<T>::operator+=。它在 MSVC14 上运行良好,但 GCC(使用 6.3.0 测试)在指定位置(当 T 没有 operator*= 时)失败并出现错误“与 '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;
    }
};

我应该怎么做?如果问题出在编译器的版本上,是否有一种简单的解决方法可以避免升级编译器?

【问题讨论】:

  • 您使用的是哪个版本的gcc?最新版本很乐意接受此代码。
  • @lubgr 我使用的是 GCC 6.3.0
  • 请做一个完整的导致编译失败的例子。
  • value*=1.0 不依赖于任何推导出的模板参数,因此您不会得到任何 SFINAE。另外,U 是否有可能不是T
  • @Mark U 应始终与 T 相同。你能告诉我一个更好的方法来检查T 是否有operator*=(double)

标签: c++ gcc compiler-errors c++14 sfinae


【解决方案1】:
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) {
    // ...
}

还在第一行添加了检查以限制 UT 相同。

【讨论】:

  • 我看你已经想通了。 :) 请注意,您也可以编写 value *= other.weight 而不是 declval,就像检查 += 一样。
  • 最好让 U 不可演绎 -> const Weighted&lt;T&gt;&amp; other
【解决方案2】:

我会这样做:

#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)
{ /*..*/ }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-09
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 1970-01-01
    • 2017-10-08
    • 2018-05-12
    相关资源
    最近更新 更多