C++ 了解别名模板
我问了一个有多处代码引用的问题:C++ 了解别名模板,c++,templates,alias,enable-if,c++17,C++,Templates,Alias,Enable If,C++17,我问了一个有多处代码引用的问题: template <typename...> using void_t = void; 模板 使用void\u t=void; 我相信我有一个普遍的误解: 为什么不在enable\u if\t或conditional\u t语句中计算传递到别名模板中的任何模板参数? 上面的代码是否只是一次对多个模板参数执行enable\u if\t 其次,我认为我对void\u t的作用有一个特定的误解。声明C++17标准定义了void\t。以下是我没有得到的:
template <typename...>
using void_t = void;
模板
使用void\u t=void;
我相信我有一个普遍的误解:
为什么不在enable\u if\t
或conditional\u t
语句中计算传递到别名模板中的任何模板参数?
上面的代码是否只是一次对多个模板参数执行enable\u if\t
其次,我认为我对void\u t
的作用有一个特定的误解。声明C++17标准定义了void\t
。以下是我没有得到的:
无效不是一个任意的名字吗?如果我仍然必须使用void\u t=void定义
模板
无论我打算在哪里使用void\t
标准化任意名称有什么意义?在Barry的例子中,来自您的链接问题:
template<typename T, typename = void>
struct has_to_string
: std::false_type { };
template<typename T>
struct has_to_string<T,
void_t<decltype(std::to_string(std::declval<T>()))>
>
: std::true_type { };
前一个版本更容易阅读,而且void\u t
不需要decltype
即可工作
如果void\t
在您的实现中可用,则无需重新定义它。标准化后,它将与标准中的任何其他别名模板一样可用
这样考虑:如果T
是int
,它有一个有效的std::to_字符串
重载,则演绎将如下所示:
template<>
struct has_to_string<int,void>
: std::true_type { };
由于默认参数,具有\u到\u字符串
->具有\u到\u字符串
。因此,让我们来寻找带有这些参数的has_to_string
的专门化
template<typename T>
struct has_to_string<T,
void_t<decltype(std::to_string(std::declval<T>()))>
>
: std::true_type { };
现在我们的专业化如下所示:
template<>
struct has_to_string<int,void>
: std::true_type { };
放弃该专门化后,我们回到主模板:
template<typename T, typename = void>
struct has_to_string
: std::false_type { };
模板
结构具有\u到\u字符串
:std::false_type{};
因此,
has_to_string
继承自std::false_type
我认为所示示例并未真正说明void_t
的用途,因为它只显示了一个用例,但当您查看
template<typename T>
struct has_to_string<T,
void_t<decltype(std::to_string(std::declval<T>()))>
>
: std::true_type { };
如您所见,即使主模板也使用void\t
来提高可读性,因为它现在与专门化匹配。这不是绝对必要的,但我喜欢。真正的力量来自于你对其他选择的思考。如果没有void\t
,专业化现在就更复杂了:
template< class T >
struct has_type_member<T, decltype(typename T::type, void())>
: std::true_type { }
整个表达式变得更长、更复杂,并且可能会遇到您忘记处理的边缘情况。这就是
void\u t
真正有帮助的地方,其他用法只是一个小小的改进,它们增加了一致性。所以你说模板使用void\u t=void代码>将在其中一个标准标题中定义?是的,完全正确。然后,您只需#包含,并使用std::void\t
@JonathanMee,它应该变成C++17@所以我想我明白了:我不能使用enable\u if\u t
因为没有“if\u this\u compiles”元函数,我需要这样做:enable\u if\u t
如此有效,我使用void\u t
作为enable\u if\u t
,带有“if\u this\u compiles”条件和void
返回类型,但是有了这个构造,decltype
SFINAE和void\u t
支持它。是的,void\u t
只是一个任意的名称。但是如果它是标准化的,它的拼写应该是std::void\t
,这样你就不必自己定义它了。同样的原因是,如果
和其他类型特征被标准化,那么启用它-这样其他程序员就可以识别它们,所有的用户就不必不断地重新定义它们。我可以看出这对于可变模板也是多么有用。@JonathanMee和更多。。。void\u t
本身的易变性甚至允许同时出现多种情况,想想void\u t
。
template<typename T>
struct has_to_string<T,
void_t<decltype(std::to_string(std::declval<T>()))>
>
: std::true_type { };
template<typename T>
struct has_to_string<T,
decltype(std::to_string(std::declval<T>()), void())
>
: std::true_type { };
// primary template handles types that have no nested ::type member
template< class, class = void_t<> >
struct has_type_member
: std::false_type { };
// specialization recognizes types that do have a nested ::type member
template< class T >
struct has_type_member<T, void_t<typename T::type>>
: std::true_type { }
template< class T >
struct has_type_member<T, decltype(typename T::type, void())>
: std::true_type { }
template< class T >
struct has_type_member<T, decltype(std::declval<typename T::type>(), void())>
: std::true_type { }