【问题标题】:SFINAE operator overloadSFINAE 运算符重载
【发布时间】:2020-04-07 14:21:28
【问题描述】:

我无法理解为什么以下代码无法编译。 sn-p 包含两个 operator& 重载,一个用于来自库头的一些可定制的枚举类,另一个来自一些应用程序代码。两个重载都使用 std::enable_if 来限制传入的类型,我看不出哪里可能有歧义?当我删除第二个运算符并重载代码编译时。

#include <cstdint>
#include <type_traits>

// Boilerplate for enum class type trait
namespace detail {

template <typename, typename = void>
struct is_enum_class_impl : std::false_type {};

template <typename T>
struct is_enum_class_impl<T, decltype((void)+T{})> : std::true_type {};

}  // namespace detail

// Enum class type trait
template <typename T>
using is_enum_class = std::integral_constant<
    bool, !detail::is_enum_class_impl<std::remove_cvref_t<T>>::value &&
              std::is_enum<std::remove_cvref_t<T>>::value>;
template <typename T>
inline constexpr bool is_enum_class_v{is_enum_class<T>::value};

template <typename T>
struct is_enum_class_flag : std::false_type {};

template <typename T>
inline constexpr bool is_enum_class_flag_v{is_enum_class_flag<T>::value};

// First operator& overload for enum class
template <typename T>
constexpr auto operator&(T lhs, T rhs)
    -> std::enable_if_t<is_enum_class_v<T> && is_enum_class_flag_v<T>, T> {
  return static_cast<T>(static_cast<std::underlying_type_t<T>>(lhs) &
                        static_cast<std::underlying_type_t<T>>(rhs));
}

namespace io {

// Enum class type with user enabled operator overload
enum class E { A = 1u << 0u, B = 1u << 1u, C = 1u << 2u };

}  // namespace io

// Specialization to enable operator overload
template <>
struct is_enum_class_flag<io::E> : std::true_type {};

namespace io {

// Some user type plus trait
struct Mask{};
template <typename T>
using is_mask = std::is_same<std::remove_cvref_t<T>, Mask>;
template <typename T>
inline constexpr bool is_mask_v{is_mask<T>::value};

// Another user type plus trait
struct State{};
template <typename T>
using is_state = std::is_same<std::remove_cvref_t<T>, State>;
template <typename T>
inline constexpr bool is_state_v{is_state<T>::value};

template <typename T>
using is_mask_or_state = std::disjunction<is_mask<T>, is_state<T>>;
template <typename T>
inline constexpr bool is_mask_or_state_v{is_mask_or_state<T>::value};

// Second operator& overload for user types
template <typename T, typename U>
constexpr auto operator&(T lhs, U rhs) -> std::enable_if_t<
    std::conjunction_v<is_mask_or_state<T>, is_mask_or_state<U>>> {
  using R = std::conditional_t<is_mask_v<T> && is_mask_v<U>, Mask, State>;
  return static_cast<R>(lhs.value() & rhs.value());
}

// Function fails to compile
void foo() {
  io::E e{io::E::A};
  // Compiler complains about invalid operands to binary expression ('io::E' and 'io::E') ?
  auto const has_a{e & io::E::A};
}

}  // namespace io

这里还有一个godbolt上的代码链接: https://godbolt.org/z/nezztu

【问题讨论】:

    标签: c++ operator-overloading sfinae


    【解决方案1】:

    你其实有ADL问题:

    要么,

    • 添加using:

      void foo() {
        using ::operator&;
      
        io::E e{io::E::A};
        auto const has_a{e & io::E::A};
      }
      

      Demo

    • 或将您的第一个 operator&amp; 移动到 namespace ioDemo

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-18
      • 1970-01-01
      • 2017-12-27
      • 1970-01-01
      • 1970-01-01
      • 2016-02-19
      • 1970-01-01
      相关资源
      最近更新 更多