【问题标题】:Using SFINAE to check if the type is complete or not [duplicate]使用 SFINAE 检查类型是否完整 [重复]
【发布时间】:2014-02-02 20:25:41
【问题描述】:

是否可以通过 SFINAE 检查类型是否已完全定义?

例如

template <class T> struct hash;
template <>        struct hash<int> {};

// is_defined_hash_type definition...

enum Enum { A, B, C, D };

static_assert (  is_defined_hash_type<int> ::value, "hash<int> should be defined");
static_assert (! is_defined_hash_type<Enum>::value, "hash<Enum> should not be defined");

解决方案不应修改 散列结构

【问题讨论】:

标签: c++ c++11 metaprogramming sfinae


【解决方案1】:

您可以创建一个is_complete 类型特征,利用它是不正确的事实来评估sizeof(T) 的不完整类型T

template <typename T>
struct is_complete_helper {
    template <typename U>
    static auto test(U*)  -> std::integral_constant<bool, sizeof(U) == sizeof(U)>;
    static auto test(...) -> std::false_type;
    using type = decltype(test((T*)0));
};

template <typename T>
struct is_complete : is_complete_helper<T>::type {};

并使用它通过确定hash&lt;T&gt; 是否完整来检查is_defined_hash_type&lt;T&gt;。 (Live at Coliru)

正如丹尼尔在他的回答中所说,这种东西的效用是有限的。 trait 实际上并不测试在您查询的代码中类型是否完整,它会测试在程序中为给定类型首次实例化 trait 时类型是否完整。

【讨论】:

  • 这对函数引用不起作用
  • @김선달 非常真实。按照公式,这仅适用于对象类型。我会清理答案,但是由于问题已作为重复项关闭,因此似乎不值得麻烦。
  • 它在程序中首次为给定类型实例化特征的点测试类型是否完整您可以添加第二个模板参数,如this answer .如果每次实例化模板都不同,那么将再次检查类型是否完整,而不重复使用之前的实例化。
【解决方案2】:

这是不可能的。原因是您必须定义 is_defined_hash_type&lt;T&gt; 但只能有 一个 定义。但是如果你稍后定义Tis_defined_hash_type&lt;T&gt; 的定义会产生不同的结果,因此会产生不同的定义,这是不允许的。这违反了 ODR(一个定义规则)。

【讨论】:

  • 接受的答案怎么样?
  • @Orient 正如凯西在他的回答中所说的那样,这个特性被设计破坏了。这就是我在回答中所解释的 - 您的程序将是非法的,即使它看起来有效,它也可能以微妙和不可预测的方式改变其含义。
  • 我认为这不构成问题,如果实例化是 TU 本地的并且没有外部链接(简单安排)。但这肯定是要牢记的。此外,可以通过添加标签类型来缓解这种情况:is_defined_hash_type&lt;T, struct my_unqiue_local_type_declaration_that_nobody_else_can_ever_see_outside_this_TU&gt;
  • @anton_rh 在 C++ 标准的限制范围内没有解决方案,__COUNTER__ 是非标准的。
  • @NikkiChumakov 它需要#include BOOST_PP_UPDATE_COUNTER() 来增加值,它不能是IS_COMPLETE 宏的一部分,所以不,它仍然不可能以可移植的、符合标准的方式。
【解决方案3】:

到目前为止,我想出的最好的是以下,这至少需要一个 typedefhash 的所有专业化中具有通用名称:

template <class T> struct hash;
template <>        struct hash<int> {
    typedef int value_type;
    };

template<class T>
constexpr bool is_defined_hash_type(typename hash<T>::value_type) {
  return true;
}

template<class T>
constexpr bool is_defined_hash_type(T) {
  return false;
}

int main()
{
  static_assert (  is_defined_hash_type< int >(0), "hash<int> should be defined");
  static_assert (! is_defined_hash_type< double>(0), "hash<Enum> should not be defined");
  return 0;
}

由于添加了参数(需要触发 SFINAE),语法非常难看。如果您认为这可能是要走的路,我会尝试进一步清理它。

免责声明:我绝不是 C++11 专家,所以我可能在使用新功能时遗漏了一些要点。在那种情况下随意开火,我会尝试纠正答案。

【讨论】:

猜你喜欢
  • 2013-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-08
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多