将包含initializer_list的参数包扩展为构造函数

时间:2011-04-27 02:14:18

标签: c++ c++11 variadic-functions initializer-list variadic-templates

我打算在即将开始的项目中使用shared_ptr,所以(不了解std::make_shared)我想把一个可变参数模板函数spnew<T>(...)写成{{1} } - 返回shared_ptr的替身。一切顺利,直到我试图使用其构造函数包含new的类型。当我尝试编译下面的最小例子时,我从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()'

奇怪的是,如果我用initializer_list代替std::make_shared,我会得到相同的错误。在任何一种情况下,当涉及spnew时,似乎错误地推断出参数,错误地将initializer_list视为空。这是一个例子:

Args...

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

2 个答案:

答案 0 :(得分: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标准尚未发布,所以这可能会改变。

答案 1 :(得分: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-list演绎加以补充。

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

基本上,裸init-list没有类型。