如何限制模板中的类型名称
How to restrict typenames in template
有一个可以接受4种不同类型的函数。它们的实现非常相似。
template< typename T >
void foo( std::string &&name, T value ){
//...
}
typename T
必须是 4 种预定义类型之一。其他类型名是不可接受的,应在编译时加以限制。
可以用C++写吗?
我至少可以想到三种方法,在我的头顶上。
第一:
namespace internal {
template< typename T >
void foo_impl( std::string &&name, T value ) {
// actual implementation here
}
}
void foo(std::string &&name, SpecialType1 value ) {
internal::foo_impl(std::forward<std::string>(name), value);
}
void foo(std::string &&name, SpecialType2 value ) {
internal::foo_impl(std::forward<std::string>(name), value);
}
第二:
template< typename T >
typename std::enable_if<std::is_same<T, SpecialType1>::value ||
std::is_same<T, SpecialType2>::value >::type
foo( std::string &&name, T value ){
//implementation here
}
第三:
template< typename T >
void foo(std::string &&name, T value){
static_assert(std::is_same<T, SpecialType1>::value ||
std::is_same<T, SpecialType2>::value,
"wrong template argument");
//implementation here
}
演示
<type_traits>
允许您将逻辑概括为类模板。这是如何工作的是我们获取模板参数T
和Ts
的参数包,然后开始检查T
是否与Head
类型列表相同。如果找到匹配项,我们从std::true_type
继承,我们就完成了。如果没有找到匹配项,我们弹出头部并递归实例化带有 Ts
尾部的相同模板。最终,如果根本找不到匹配项,参数包大小将降至零,编译器将实例化从 std::false_type
继承的基本模板类。请观看此视频,了解沃尔特·E·布朗先生的更好和部门解释。
template<class T, class...> struct is_any_of: std::false_type{};
template<class T, class Head, class... Tail>
struct is_any_of<T, Head, Tail...>: std::conditional_t<
std::is_same<T, Head>::value,
std::true_type,
is_any_of<T, Tail...>>
{};
现在我们可以用几乎英文的措辞使用enable_if。
#include <type_traits>
#include <string>
template<
class T,
class = std::enable_if_t<is_any_of<T, int, float, unsigned, double>::value>
>
void foo(std::string &&str, T value) {}
int main()
{
foo(std::string{"hello"}, 3);
foo(std::string{"world"}, '0'); //compile-time error
}
SFANIE是一种语言功能,一种工具,它被用来或滥用一些人来实现你的要求,
标准库组件 std::enable_if 允许创建替换失败,以便根据编译时评估的条件启用或禁用特定的重载。 仅供参考 http://en.cppreference.com/w/cpp/language/sfinae。
请注意,std::conditional_t<>
和 std::enable_if_t<>
分别是 std::conditional<>::type
和 std::enable_if<>::type
的简写。您可以在代码中简单地替换它们,但应该在enable_if
之前放置typename
关键字。
我见过人们做的一件事是使用 std::enable_if
.我不知道你的 4 种类型到底是什么,所以这是一个有两种类型的例子 int
和 float
.
using myType = std::enable_if<
std::is_same<int, T>::value ||
std::is_same<float, T>::value, T >::type;
只有当T
正好int
或float
时,myType
才存在。希望对您有所帮助!
我参加聚会迟到了,但也许有人会发现这很有用。
从C++20
起,可以使用约束和概念来过滤模板中可能的typename
。
语法是这样的:
template <typename T>
requires std::is_integral_v<T>
auto func(T any_integer) {
...
};
// Or, you can also do:
template <typename T>
concept Integer = std::is_integral_v<T>;
template <Integer T>
auto func(T any_integer) {
...
};
// Or, an even better approach:
auto func(Integer auto any_integer) {
...
};
我更喜欢最后一个,因为它很好,很干净。但是,这只是我的意见。
以下是对func()
的一些有效调用:
func(int{}); // OK!
func(long{}); // OK!
func(bool{}); // Yes, it's OK too!
func(char{}); // Yes, it's OK too!
现在,一些对func()
的无效调用:
func(double{}); // Compiler error!
func(std::string{}); // Compiler error!
编译器还会根据您的使用情况给出干净的错误消息:
注意:候选:"模板需要is_integral_v无效功能(T(">
或
注意:候选:"模板需要整数自动函数(T(">
或
注意:候选:"模板需要整数自动:15 自动功能(自动:15(">
引用:
- https://en.cppreference.com/w/cpp/types/is_integral
- 将使用/类型定义限制为类范围
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- 如何使用类型特征将函数的通用引用参数限制为 r 值引用?
- 将-Wtype限制与类型泛型代码一起使用
- 将变量模板限制为类型列表
- 限制模板化类数据类型
- 类的可变参数模板部分专用化,用于限制模板参数的类型
- 搜索并限制为特定文件类型VS2017
- 数据对齐:限制内存地址为数据类型大小倍数的原因
- 如何将模板限制为特定类型?
- C++:“enable_if”用于限制支持特定算术运算的类型
- 限制类模板类型
- 两种类型转换有何不同?
- 正确的方法将功能限制为特定数据类型
- 如何检查 stdin 中的数字是否小于给定类型的数字限制
- SFINAE将实例化类型限制为std::chrono::duration类型
- 数据类型的限制
- C++11对lambda返回类型的限制
- 访问者模式与对输入类型有限制的向下转换
- C++中"char"类型的限制