如何通过参数的某些质量而不是其确切类型来指定参数类型

How do I specify a parameter type by some quality of the parameter rather than its exact type?

本文关键字:类型 参数 何通过      更新时间:2024-09-28

所以我在C++中有一个函数,如下所示:

void print_vec(std::vector<int> v) {
for (int i: v) {
std::cout << i << ' ';
}
std::cout << std::endl;
}

这很有效,但只适用于int向量。我想要像一样的东西

void print_iter(Iterable<CanDoCout> iterable) {
for (auto i: iterable) {
std::cout << i << ' ';
}
std::cout << std::endl;
}

如何实现print_iter?或者,我如何找到如何实现这样的通用函数?

您要查找的是模板:

template <class T>
void print_iter(const T& iterable) {
for (const auto& i: iterable) {
std::cout << i << ' ';
}
std::cout << std::endl;
}

您可以更进一步,使用概念或SFINAE将模板限制为仅接受您应用的操作的类型。

假设您可以访问C++20,这就是您如何使用以下概念限制模板接受的类型:

template <typename T>
concept printable = requires(T t)
{
std::cout << t;
};
template <std::ranges::range T>
requires printable<std::ranges::range_value_t<T>>
void print_iter(const T &iterable)
{
for (const auto &it : iterable)
std::cout << it << ' ';
std::cout << 'n';
}

concept printable = ...printable定义为一个概念(一组(通常(类型的要求(。假设tT类型的变量,当表达式std::cout << t良好地形成时,满足这个概念。

print_iter():的定义中

  • template <std::ranges::range T>template <typename T>相同,只是它使用概念std::ranges::range(即您所称的"可迭代"(来约束类型。

  • requires printable<std::ranges::range_value_t<T>>T添加了一个额外的约束:它要求类型std::ranges::range_value_t<T>(T的元素类型(满足我们的概念printable

如果你不想使用C++20概念(或Rust特性(,并且你仍然希望你的函数只应用于可迭代类型(因为没有人喜欢SFINAE错误(,那么一种技术是要求它有一个const_iterator:

template <typename T>
void print_range(const T& iterable, typename T::const_iterator = T{}.cbegin()) {
for (const auto& elem : iterable) {
std::cout << elem << ' ';
}
std::cout << std::endl;
}

在这种情况下,const_iterator参数必须是默认的伪参数。我之前建议使用两个迭代器,但这需要调用方明确模板类型,这并不酷。

选择const_iterator/cbegin作为可迭代(而不是一般的这种技术(的定义特征,一个公平的批评是,并非所有可迭代的东西都有这个接口。但这并不是一个真正的障碍,因为调用者可以用这个接口将其封装在一个类型中。例如,在C字符串的情况下为string_view。