为什么函数模板的这种自定义类型特征检查不起作用?

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

我已经用测试用例编写了这种类型特征:

template <typename T, typename = int>
struct is_serializable: false_type {};

template <typename T>
struct is_serializable<
    T, 
    enable_if_t<
        is_same_v<
            decltype(declval<T>().serialize(declval<gsl::span<uint8_t>>())),
            gsl::span<uint8_t>
        >
    >
> : true_type {};

template <typename T>
constexpr bool is_serializable_v = is_serializable<T>::value;

struct Serialize {
  gsl::span<uint8_t> serialize(gsl::span<uint8_t> input) {
    return input
  }
};

static_assert(is_serializable_v<Serialize>, "***");

这个效果很好。

然后我通过添加模板参数来选择字节序来扩展整个内容,如下所示:

enum class Endian {
  LITTLE,
  BIG
}

template <typename T, typename = int>
struct is_serializable: false_type {};

template <typename T>
struct is_serializable<
    T, 
    enable_if_t<
        is_same_v<
            decltype(declval<T>().serialize<Endian::LITTLE>(declval<gsl::span<uint8_t>>())),
            gsl::span<uint8_t>
        > &&
        is_same_v<
            decltype(declval<T>().serialize<Endian::BIG>(declval<gsl::span<uint8_t>>())),
            gsl::span<uint8_t>
        >
    >
> : true_type {};

template <typename T>
constexpr bool is_serializable_v = is_serializable<T>::value;

struct Serialize {
  template <Endian endian>
  gsl::span<uint8_t> serialize(gsl::span<uint8_t> input) {
    return input
  }
};

static_assert(is_serializable_v<Serialize>, "***");

这不再起作用了。类型特征返回 false。

为了看看发生了什么,我尝试过


static_assert(
    is_same_v<
        decltype(declval<Serialize>().serialize<Endian::LITTLE>(declval<gsl::span<uint8_t>>())),
        gsl::span<uint8_t>
    > &&
    is_same_v<
        decltype(declval<Serialize>().serialize<Endian::BIG>(declval<gsl::span<uint8_t>>())),
        gsl::span<uint8_t>
    >,
    "***"
)

这与特征中的enable_if参数是一样的,这给了我

true
。 但如果这是
true
,则 is_serialized_v 类型特征也应该是
true
,不是吗?我现在有多傻?

免责声明:

  1. 我正在使用 g++ 10.5.0 和 C++17,现在无法进一步提高。我还尝试过 g++ 13.3.0 和 C++20 只是为了看看会发生什么,它是相同的行为。
  2. 我现在使用 NixOS,但代码适用于在 Nordic nRF52840 上运行的嵌入式项目。我也在 Ubuntu 20.04 LTS 下进行了尝试,正如预期的那样,这并没有改变任何东西。
  3. 为了便于阅读,我省略了适用的
    std::
    前缀。我添加了例如
    using std::declval;
    等位于文件开头。
  4. 我正在使用 this gsl 实现,并且从未遇到过任何问题。标头包含在文件的开头。
c++ templates metaprogramming type-traits
1个回答
0
投票

type
的默认
enable_if
void

仅当主模板的第二个模板参数为

void
:

时,才可以使用您的模板特化
template <typename T, typename = void>
struct is_serializable: false_type {};

你需要使用这样的语法:

decltype(declval<T>().template serialize<Endian::LITTLE>

告诉编译器

<Endian
左尖括号打开模板参数列表,而不是较少运算符。

工作演示

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