将包含initializer_list的参数包扩展到构造函数
我打算在即将到来的项目中大量使用 shared_ptr
,所以(不知道 std::make_shared
)我想编写一个可变参数模板函数 spnew< ;T>(...)
作为 shared_ptr
返回 new
的替代品。一切都很顺利,直到我尝试使用其构造函数包含 initializer_list
的类型。当我尝试编译下面的最小示例时,我从 GCC 4.5.2 中得到以下信息:
In function 'int main(int, char**)': too many arguments to function 'std::shared_ptr spnew(Args ...) [with T = Example, Args = {}]' In function 'std::shared_ptr spnew(Args ...) [with T = Example, Args = {}]': no matching function for call to 'Example::Example()'
奇怪的是,如果我用 std::make_shared
替换 spnew
,我会得到相同的错误。无论哪种情况,当涉及 initializer_list
时,它似乎都错误地推导了参数,错误地将 Args...
视为空。这是一个例子:
#include <memory>
#include <string>
#include <vector>
struct Example {
// This constructor plays nice.
Example(const char* t, const char* c) :
title(t), contents(1, c) {}
// This one does not.
Example(const char* t, std::initializer_list<const char*> c) :
title(t), contents(c.begin(), c.end()) {}
std::string title;
std::vector<std::string> contents;
};
// This ought to be trivial.
template<class T, class... Args>
std::shared_ptr<T> spnew(Args... args) {
return std::shared_ptr<T>(new T(args...));
}
// And here are the test cases, which don't interfere with one another.
int main(int argc, char** argv) {
auto succeeds = spnew<Example>("foo", "bar");
auto fails = spnew<Example>("foo", {"bar"});
}
这只是我的疏忽,还是一个错误?
I intend to use shared_ptr
quite a bit in an upcoming project, so (not being aware of std::make_shared
) I wanted to write a variadic template function spnew<T>(...)
as a shared_ptr
-returning stand-in for new
. Everything went smoothly till I attempted to make use of a type whose constructor includes an initializer_list
. I get the following from GCC 4.5.2 when I try to compile the minimal example below:
In function 'int main(int, char**)': too many arguments to function 'std::shared_ptr spnew(Args ...) [with T = Example, Args = {}]' In function 'std::shared_ptr spnew(Args ...) [with T = Example, Args = {}]': no matching function for call to 'Example::Example()'
Oddly enough, I get equivalent errors if I substitute std::make_shared
for spnew
. In either case, it seems to be incorrectly deducing the parameters when an initializer_list
is involved, erroneously treating Args...
as empty. Here's the example:
#include <memory>
#include <string>
#include <vector>
struct Example {
// This constructor plays nice.
Example(const char* t, const char* c) :
title(t), contents(1, c) {}
// This one does not.
Example(const char* t, std::initializer_list<const char*> c) :
title(t), contents(c.begin(), c.end()) {}
std::string title;
std::vector<std::string> contents;
};
// This ought to be trivial.
template<class T, class... Args>
std::shared_ptr<T> spnew(Args... args) {
return std::shared_ptr<T>(new T(args...));
}
// And here are the test cases, which don't interfere with one another.
int main(int argc, char** argv) {
auto succeeds = spnew<Example>("foo", "bar");
auto fails = spnew<Example>("foo", {"bar"});
}
Is this just an oversight on my part, or a bug?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你可以这样做 -
尽管通用模板是类型安全的,因为编译器会抱怨
如果传递的类型不可转换为 const char *,则为
contents.push_back
。如上所述,您的代码在 gcc 4.6 上运行良好,但是您收到的警告在此处进行了解释
为什么-doesnt-my-template-accept-an-initializer-list< /a>,并且可能不是标准
兼容,尽管 c++0x 标准尚未发布,因此这可能会改变。
You could do this -
This, despite the generic templates is type safe as the compiler will complain about
the
contents.push_back
if the passed type is not convertible to aconst char *
.As described above, your code was working fine with gcc 4.6 however the warning you get is explained here
why-doesnt-my-template-accept-an-initializer-list, and is possibly not standards
compliant, although the c++0x standard is yet to be published so this could change.
使用带有警告的 gcc-4.7(可能也适用于 gcc-4.6,只是分支):
我不确定为什么有人会想要抱怨 init-list 推导。
有一个相关的线程:
为什么我的模板不接受初始化列表
基本上,裸露的初始化列表没有类型。
With gcc-4.7 (probably would work on gcc-4.6 too, just branched) with warnings:
I'm not sure why anyone would want to beef about init-list deduction though.
There is a related thread:
Why doesn't my template accept an initializer list
Basically, a bare init-list doesn't have a type.