Visual Studio 2019今天发布了16.3版本更新,加入了C++20的concept支持,在此记录一下concept的用法:
concept示例
1.限制只能打印int类型
//std::enable_if实现
template <typename T>
void print_int(std::enable_if_t<std::is_same_v<int, std::decay_t<T>>, T> v)
{
std::cout << v << std::endl;
}
int main()
{
print_int(1); //error C2783: “void print_int(enable_if<std::is_same_v<int,decay<_Ty>::type>,T>::type)”: 未能为“T”推导 模板 参数
print_int<int>(1);
print_int<double>(1.0); //error C2672: “print_int”: 未找到匹配的重载函数
}
//concept实现
template <class T>
concept IntLimit = std::is_same_v<int, std::decay_t<T>>; //制约T塌陷后的类型必须与int相同
template <IntLimit T>
void print_int(T v)
{
std::cout << v << std::endl;
}
int main()
{
print_int(1);
print_int(1.0); //error C2672: “print_int”: 未找到匹配的重载函数
}
可以看到concept比之前的实现更加简洁易懂。
2.require关键字
//限定只能调用存在name成员函数的类
class A
{
public:
std::string_view name() const { return "A"; }
};
class B
{
public:
std::string_view class_name() const { return "B"; }
};
template <typename T>
concept NameLimit = requires(T a)
{
a.name(); //制约T的实例a必须要有name成员函数
};
template <NameLimit T>
void print_name(T a)
{
std::cout << a.name() << std::endl;
}
int main()
{
A a;
B b;
print_name(a);
print_name(b); //error C2672 : “print_name”: 未找到匹配的重载函数
}
//限定只能调用返回值可以转换为std::string的函数
template <typename T>
concept ReturnLimit = requires(T t)
{
{t()} -> std::convertible_to<std::string> ; //函数返回值必须可以转换为std::string
std::is_function<T>; //T必须为函数
};
template <ReturnLimit T>
void print_string(T func)
{
std::cout << func() << std::endl;
}
std::string str1()
{
return "123";
}
constexpr const char* str2()
{
return "str2";
}
std::basic_string<char8_t> str3()
{
return u8"str3";
}
int main()
{
std::string t;
t = std::string_view("213");
print_string(&str1);
print_string(&str2);
print_string(&str3); //error C2672: “print_string”: 未找到匹配的重载函数
return 0;
}
concept可以和if constexpr结合使用
class A
{
public:
constexpr std::string_view name() const { return "A"; }
};
class B
{
public:
constexpr std::string_view class_name() const { return "B"; }
};
template <typename T>
concept CA = requires(T a)
{
a.name();
};
template <typename T>
concept CB = requires(T b)
{
b.class_name();
};
template <typename T>
void print_class(const T& t)
{
if constexpr (CA<T>)
{
std::cout << t.name() << std::endl;
}
else if constexpr (CB<T>)
std::cout << t.class_name() << std::endl;
}
int main()
{
A a;
B b;
print_class(a);
print_class(b);
return 0;
}
打印出结果:
A
B