7

我打算用shared_ptr颇有几分在即将开展的项目,所以(没有意识到std::make_shared)我想写一个可变参数模板功能spnew<T>(...)shared_ptr -returning待机为new 。一切都很顺利,直到我试图使用构造函数包含initializer_list的类型。我从GCC 4.5.2以下,当我尝试编译下面的小例子:扩大参数包含initializer_list同构造函数

 
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_sharedspnew。在任何一种情况下,当涉及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"}); 
} 

这只是我的一个疏忽,或者一个错误?

+1

顺便说一句,有'std :: make_shared'。 – GManNickG 2011-04-27 02:18:18

+0

@GMan:是的,我发现并将使用它,但我仍然好奇我写的是什么。 – 2011-04-27 02:20:11

+0

@GMan:实际上,在我的例子中,尝试用'make_shared'代替'spnew',它仍然失败,出现了同样错误的'failed'情况。所以,现在至少我知道错误不在哪里... – 2011-04-27 02:22:56

回答

0

使用GCC-4.7(可能会工作在GCC-4.6也只是支)与警告:

foo.cpp: In function ‘int main(int, char**)’: 
foo.cpp:29:47: warning: deducing ‘Args ...’ as ‘std::initializer_list<const 
char*>’ [enabled by default] 
foo.cpp:22:20: warning: in call to ‘std::shared_ptr<_Tp1> spnew(Args ...) 
[with T = Example, Args = {const char*, std::initializer_list<const 
char*>}]’ [enabled by default] 
foo.cpp:29:47: warning: (you can disable this with -fno-deduce-init-list) 
[enabled by default] 

我不知道为什么会有人想虽然牛肉有关init列表扣除。

有一个相关主题: Why doesn't my template accept an initializer list

基本上,裸初始化列表没有一个类型。

+1

至于牛肉,默认的初始列表推断行为是一个较旧的推测扩展,它可能与更近的提议相冲突,这就是为什么'-fno-deduce-init-list'出现的原因。 – 2011-04-27 04:08:51

1

你可以做到这一点 -

#include <memory> 
#include <string> 
#include <iostream> 
#include <vector> 

struct Example { 

    template<class... Args> 
    Example(const char* t, Args... tail) : title(t) 
    { 
     Build(tail...); 
    } 

    template<class T, class... Args> 
    void Build(T head, Args... tail) 
    { 
     contents.push_back(std::string(head)); 
     Build(tail...); 
    } 

    template<class T> 
    void Build(T head) 
    { 
     contents.push_back(std::string(head)); 
    } 

    void Build() {}   

    std::string title; 
    std::vector<std::string> contents; 

}; 

template<class T, class... Args> 
std::shared_ptr<T> spnew(Args... args) { 
    return std::shared_ptr<T>(new T(args...)); 
} 

int main(int argc, char** argv) { 
    auto succeeds = spnew<Example>("foo", "bar"); 
    auto fails = spnew<Example>("foo", "bar", "poo", "doo"); 

    std::cout << "succeeds->contents contains..." << std::endl; 
    for (auto s : succeeds->contents) std::cout << s << std::endl; 

    std::cout << std::endl << "fails->contents contains..." << std::endl; 
    for (auto s : fails->contents) std::cout << s << std::endl; 
} 

此,尽管通用模板是类型安全的,因为编译器会抱怨 的contents.push_back如果传递的类型不是转化为const char *

如上所述,你的代码是用gcc 4.6工作正常,但是你得到的警告在此说明 why-doesnt-my-template-accept-an-initializer-list,而且可能不标准 兼容,虽然的C++ 0x标准尚未公布,以便这可能更改。

相关问题