gpt4 book ai didi

c++ - 检测习语 : why does the condition have to be a `using` directive?

转载 作者:行者123 更新时间:2023-11-28 05:08:32 24 4
gpt4 key购买 nike

编辑:this我的另一个问题侧重于这个问题的简化版本,可能更容易理解。

我写了一个小片段来重现 std::experimental::is_detected ( here ) 的行为。我的实现基本上取自 cppreference,但我去掉了 Default 模板参数。

我的问题是:在下面的代码片段中,为什么 has_type(要检查的条件)have 是一个 using 声明并且不能,例如结构(在这种情况下 is_detected 返回错误结果)?

/***** is_detected definition *****/
template<typename...Args>
using void_t = void;

template<typename Void, template<class...> class Op, typename ...Args>
struct Detector {
static constexpr bool value = false;
};

template<template<class ...> class Op, typename ...Args>
struct Detector<void_t<Op<Args...>>, Op, Args...> {
static constexpr bool value = true;
};

template<template<class...> class Op, typename...Args>
using is_detected_t = Detector<void, Op, Args...>;
/****************************/

/***** is_detected test *****/
// two dummy types on which to test a condition
struct Yes { using type = void; };
struct No { };

// the condition to test
template<typename T>
using has_type = typename T::type;
// struct has_type { using type = typename T::type; }; // does not work as intended!

int main() {
static_assert(is_detected_t<has_type, Yes>::value, "");
static_assert(!is_detected_t<has_type, No>::value, "");
return 0;
}

最佳答案

查看检测器实际如何使用 has_type 可能会有所帮助:

template<template<class ...> class Op, typename ...Args>
struct Detector<void_t< Op<Args...>>, Op, Args...> {
// ^^ ^^
// has_type Yes/No
static constexpr bool value = true;
};

为了匹配此特化,编译器必须确保 Op<Args...> 在用实际参数(OpArgs.../has_type)替换参数(YesNo)时,必须命名一个类型(因为这就是模板 void_t 作为第一个模板参数所需要的)。

由于 has_type 不是类型,而是某种类型的别名,因此它必须查看别名是否命名为类型。

对于 Yes 这将是 Yes::type ,这也是 void 的别名。 void 是一个类型,所以一切正常,特化匹配,valuetrue

对于 No 这将是 No::type ,它不存在(毕竟 No 没有成员 type)。因此,替换失败(但这不是错误,SFINAE),无法使用特化。因此编译器选择基本模板,其中 valuefalse


现在当您按如下方式定义 has_type 时会发生什么:

template<typename T>
struct has_type { using type = typename T::type; }

然后上面的特化需要(在 No 的情况下)类型 has_type<No> 存在。 has_type 是一个类模板,给定某种类型( No 是一种类型,所以一切都很好)“产生”一种类型。因此,has_type<No> 是一种类型。因此特化匹配,valuetrue

此时不需要 has_type<No>成员您甚至可以使用 template<typename> struct has_type;(只有声明,没有定义)。也就是说,它可能是一个不完整的类型:

A template argument for a type template parameter must be a type-id, which may name an incomplete type [..]

http://en.cppreference.com/w/cpp/language/template_parameters

内容仅在编译器实际需要时才重要,例如用于创建该类型的对象:

// Class template with some random members.
template<typename T>
struct Foo {
using baz = typename T::baz;
constexpr static int value = T::value * 42;
};

// Class template which is even only declared
template<typename X> struct Bar; // no definition

// Does not use its template parameter in any way. Needs just a type name.
template<typename> struct Defer {};

int main() {
Defer<Foo<int>> ok;
Defer<Bar<int>> ok_too;
// Foo<int> fail;
// Bar<int> fail_too;
return 0;
}

这种机制通常用于“类型标签”,例如可用于从单个模板创建具有相同“内容”的不同类型:

template<typename /* TAG */, typename ValueType>
struct value_of_strong_type {
ValueType value;
// ...
};

struct A_tag; // no definition
using A = value_of_strong_type<A_tag, int>;
struct B_tag; // no definition
using B = value_of_strong_type<B_tag, int>;

AB 的行为相同,但不能相互转换,因为它们是完全不同的类型。


要使检测器使用您展示的类模板,您需要进行以下专门化:

template<template<class ...> class Op, typename ...Args>
struct Detector<void_t<typename Op<Args...>::type>, Op, Args...> {
// ^^^^^^^^ ^^^^^^
static constexpr bool value = true;
};

虽然你不能只添加它,否则你会遇到模棱两可的解析错误。

关于c++ - 检测习语 : why does the condition have to be a `using` directive?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44041722/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com