C++ 使用SFINAE的非模板类中的模板函数重载 TL;博士

C++ 使用SFINAE的非模板类中的模板函数重载 TL;博士,c++,c++11,sfinae,guideline-support-library,C++,C++11,Sfinae,Guideline Support Library,一个非模板化类中的两个模板化和重载的非模板化成员函数都应该最终通过同一个成员函数进行路由以执行实际工作。所有重载和模板化都是为了将“数据缓冲区”转换为gsl::span类型(本质上是与来自 代码墙 如果这无法实现,我想知道原因 我在MSVC 2017上启用了C++17。第一个答案有点错误,出于某些原因,我完全被gsl搞糊涂了。我认为这是一件非常特别的事情。我没有使用指南支持库,尽管我已经看到了它,而且它看起来不错。 修复了代码以正确使用gsl::spantype struct A { en

一个非模板化类中的两个模板化和重载的非模板化成员函数都应该最终通过同一个成员函数进行路由以执行实际工作。所有重载和模板化都是为了将“数据缓冲区”转换为
gsl::span
类型(本质上是与来自


代码墙 如果这无法实现,我想知道原因


我在MSVC 2017上启用了C++17。

第一个答案有点错误,出于某些原因,我完全被gsl搞糊涂了。我认为这是一件非常特别的事情。我没有使用指南支持库,尽管我已经看到了它,而且它看起来不错。 修复了代码以正确使用
gsl::span
type

struct A {
  enum class E1 : uint8_t { v1 = 10, v2, v3, v4 };

private:
  template <typename T>
  static auto make_span(T& _x) ->
    typename std::enable_if<std::is_convertible<T&, gsl::span<std::byte>>::value,
                            gsl::span<std::byte>>::type {
    std::cout << "conversion" << std::endl;
    return _x;
  }

  template <typename T>
  static auto make_span(T& _x) ->
    typename std::enable_if<!std::is_convertible<T&, gsl::span<std::byte>>::value,
                            gsl::span<std::byte>>::type {
    std::cout << "cast" << std::endl;
    return {reinterpret_cast<std::byte*>(&_x), sizeof(T)};
  }

public:
  template <typename T, typename U>
  bool f(T _i, U& _buf) {
    static_assert(
      std::is_convertible<U&, gsl::span<std::byte>>::value || std::is_trivial<U>::value,
      "The object must be either convertible to gsl::span<std::byte> or be of a trivial type");

    const auto i = static_cast<uint8_t>(_i);
    const auto span = make_span(_buf);
    std::cout << "f() uint8_t{" << (int)i << "} with " << span.size() << " elements\n";
    return true;
  }
};
结构A{ 枚举类E1:uint8{v1=10,v2,v3,v4}; 私人: 模板 静态自动生成(T和x)-> typename std::enable_if::type{ std::cout::value, gsl::span>::类型{
std::cout您确定它应该在
a.f(1,buf)
a.f(a::E1::v1,buf)
情况下调用(a)吗?更像是应该调用(c),但不会,因为它被
enable\u如果
条件忽略。标准规定“纯重载”如果找到了正确的匹配项,则函数是在模板上选择的,这是真的,但是在这些情况下,您传递的是
std::array
,而使用
gsl::span
声明的方法。因此,显然类型不同。如果传递的是
gsl::span
,那么就很清楚了。为什么您希望它调用(a)和(b)?我的问题是“如何使它调用a)而不是b)”。好吧,这是问题的一部分,无论如何这是“足够接近的”。这不完全是一个解决方案(因此不标记它),但肯定是对我的解决方案的改进。您还可以检查
f
中的
T
类型是否是
E1
uint8\T
静态断言中。
struct A {
// ...
template<typename T> bool f(uint8_t _i1, T& _val);
template<typename T> bool f(E1 _i1, T& _val);
};

template<> bool f<is_PoD<T> && not_like_gsl_span<T>>(uint8_t /*...*/}
template<> bool f<is_PoD<T> && not_like_gsl_span<T>>(E1 /*...*/}
template<> bool f<is_like_gsl_span<T>>(uint8_t /*...*/}
template<> bool f<is_like_gsl_span<T>>(E1 /*...*/}
struct A {
  enum class E1 : uint8_t { v1 = 10, v2, v3, v4 };

private:
  template <typename T>
  static auto make_span(T& _x) ->
    typename std::enable_if<std::is_convertible<T&, gsl::span<std::byte>>::value,
                            gsl::span<std::byte>>::type {
    std::cout << "conversion" << std::endl;
    return _x;
  }

  template <typename T>
  static auto make_span(T& _x) ->
    typename std::enable_if<!std::is_convertible<T&, gsl::span<std::byte>>::value,
                            gsl::span<std::byte>>::type {
    std::cout << "cast" << std::endl;
    return {reinterpret_cast<std::byte*>(&_x), sizeof(T)};
  }

public:
  template <typename T, typename U>
  bool f(T _i, U& _buf) {
    static_assert(
      std::is_convertible<U&, gsl::span<std::byte>>::value || std::is_trivial<U>::value,
      "The object must be either convertible to gsl::span<std::byte> or be of a trivial type");

    const auto i = static_cast<uint8_t>(_i);
    const auto span = make_span(_buf);
    std::cout << "f() uint8_t{" << (int)i << "} with " << span.size() << " elements\n";
    return true;
  }
};