SFINAE运算符重载

问题描述 投票:0回答:1

我无法理解为什么以下代码无法编译。该代码段包含两个操作符和重载,一个用于库头中的一些可自定义的枚举类,另一个用于某些应用程序代码。两种重载都使用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个回答
1
投票

您实际上有ADL问题:

两者之一

  • 添加using

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

    Demo

  • 或在operator&中移动您的第一个namespace ioDemo

© www.soinside.com 2019 - 2024. All rights reserved.