我有一个问题要为一个类编写一个基于范围的构造函数,但找不到合适的措辞来搜索google上的帮助。
假设我正在写一个简单的类,比如vector,它涉及一个基于范围的构造函数,它将范围中的元素插入到当前容器中:
// foo.h
#ifndef FOO_H
#define FOO_H
#include <iostream>
class Foo {
public:
Foo() {
std::cout << "Default constructor called" << std::endl;
}
template<class InputIterator> Foo(InputIterator first, InputIterator last) {
std::cout << "Range based constructor called" << std::endl;
}
Foo(size_t n, int val) {
std::cout << "size_t, int constructor called" << std::endl;
}
};
#endif // FOO_H
并拥有一个cpp文件
#include <iostream>
#include <vector>
#include "foo.h"
using std::cout; using std::endl;
int main() {
std::vector<int> v(10, 5);
Foo f_default;
Foo f_range(v.begin(), v.end());
Foo f_int(314, 159); // want this to call size_t, int ctctr
return 0;
}
在main的第三行,我们创建了一个Foo f_int(314, 159)
,直觉上我们想要调用size_t,int构造函数。但是它匹配范围的通用模板构造函数。有没有办法在C ++中解决这样的问题?我觉得我错误地处理了基于编写范围的构造函数。
我可以想象你可以使用模板专业化,但实际上并没有看到如何。
可能发生这种情况的一个例子是,如果我们正在编写一个向量类,其中有一个基于size_t和默认值的构造函数(将在类上进行模板处理,但我在这里进行了简化)和另一个基于迭代器的构造函数的范围内。
答案 0 :(得分:4)
构造函数模板在第三种情况下更匹配,因为您传递了两个int
参数,而Foo(size_t n, int val)
需要进行int
到size_t
转换第一个论点。如果您将代码修改为
Foo f_int(static_cast<size_t>(314), 159);
调用所需的构造函数。但是,当然,这不是一个好的解决方案,因为它很容易意外地调用错误的构造函数。相反,您可以使用SFINAE从重载决策集中删除构造函数模板,方法是确保参数类型为迭代器。
template<class InputIterator,
class = std::enable_if_t<
std::is_base_of<
std::input_iterator_tag,
typename std::iterator_traits<InputIterator>::iterator_category
>{}
>
>
Foo(InputIterator first, InputIterator last) {
std::cout << "Range based constructor called" << std::endl;
}
如果查看表here,您可以读取的所有迭代器都是 InputIterators 或派生类型。所以上面的代码检查传递给构造函数的InputIterator
类型是否属于该类型或从该类型派生的东西。